Pular para o conteúdo principal
Versão: main (dev) 🚧

ITLab.Template.DevPack.Middleware

Provides ASP.NET Core middleware for culture negotiation, 404 handling, unauthenticated request fallback, identity bridging and domain-based tenant resolution.

Componentes

TipoNomeResponsabilidade
ClassCultureMiddlewareSets request culture from the Accept-Language header (fallback: en-US)
Sealed ClassDevPackIdentityContextMiddlewareBridges HttpContext.User claims into AsyncLocalCurrentUserAccessor so ICurrentUser consumers see the authenticated user
Sealed ClassTenantResolutionMiddlewareResolves the tenant from the request host and cross-checks it against the token tenant (opt-in via MultiTenancyOptions.EnableDomainValidation)
ClassNotFoundMiddlewareIntercepts 404 responses and returns a structured error payload
ClassUnauthenticatedFallbackMiddlewareReturns 401 Unauthorized for requests that reach the pipeline without an identity

Como usar

// Register middleware in the correct pipeline order.
app.UseMiddleware<CultureMiddleware>();
app.UseAuthentication();
app.UseDevPackIdentityContext(); // bridge HttpContext.User → AsyncLocal
app.UseMiddleware<UnauthenticatedFallbackMiddleware>();
app.UseAuthorization();
app.UseMiddleware<NotFoundMiddleware>();

Order matters: UseAuthentication populates HttpContext.User; UseDevPackIdentityContext projects the claims into AsyncLocalCurrentUserAccessor (consumed by RoleBasedPermissionEvaluator and other ICurrentUser consumers); UseAuthorization then evaluates policies. Without the bridge, ICurrentUser.UserRoles is empty in production → 403 on every protected endpoint.

Domain tenant resolution (TenantResolutionMiddleware)

When the host name itself carries tenant identity (acme.app.example.com → "acme"), register UseDevPackTenantResolution() after the identity bridge and before UseAuthorization:

app.UseAuthentication();
app.UseDevPackIdentityContext(); // token tenant → ICurrentUser.TenantId
app.UseDevPackTenantResolution(); // resolve host tenant + cross-check vs token
app.UseAuthorization();

The middleware is a no-op unless MultiTenancyOptions.EnableDomainValidation is true. When enabled, it resolves the host tenant via ITenantResolver, maps it to an id and validates membership through the consumer-implemented ITenantAccessValidator, then cross-checks that id against ICurrentUser.TenantId (the token tenant) — a token issued for tenant A replayed against tenant B's host is rejected. Status codes: 401 (no token tenant / unresolvable host / host-vs-token mismatch), 404 (host maps to no tenant), 403 (user has no membership). Anonymous requests and MultiTenancyOptions.ExcludedPaths pass through. The ordering after the bridge is essential — the cross-check needs the token tenant already on ICurrentUser.

O que não fazer

  • Do not place CultureMiddleware after UseRouting — culture must be set before route handlers execute.
  • Do not use UnauthenticatedFallbackMiddleware as a substitute for proper [Authorize] annotations.
  • Do not register UseDevPackTenantResolution() before UseDevPackIdentityContext() — the cross-check reads ICurrentUser.TenantId, which the bridge populates. Wrong order silently skips the check (token tenant always 0).
  • Do not forget IHttpContextAccessor when enabling domain resolution — DomainTenantResolveContributor resolves the request through it.

Extensão pelo produto

  • Products can extend NotFoundMiddleware to include product-specific 404 response bodies.
  • Products can extend CultureMiddleware to resolve culture from user profile settings instead of the request header.