本文转载自微信公众号《DotNET技术圈》,作者BenFoster。转载本文请联系DotNET技术圈公众号。在.NET5.0中自定义授权响应ASP.NETCore授权框架中一个经常请求的[1]功能是能够在授权失败时自定义HTTP响应。以前,唯一的方法是直接在您的控制器中(或通过过滤器)调用IAuthorizationService到授权服务,类似于基于资源的授权方法[2]或实现您自己的授权过滤器[3]。从.NET5.0开始,您现在可以通过实现IAuthorizationMiddlewareResultHandler接口来自定义HTTP响应;中间件在授权失败时由授权框架自动调用。Microsoft文档站点上对此进行了记录[4],但我花了一段时间才找到适合我的特定用例的内容。问题我一直在采取措施将旧的ASP.NETWebAPI应用程序移植到.NETCore5.0。此API具有分层URI结构,因此大多数端点将位于“站点”资源下,例如:/sites/sites/{siteId}/sites/{siteId}/blog验证用户是否有权访问给定的站点,应用程序该程序以前使用自定义操作过滤器来提取siteId路由参数并根据用户的声明对其进行验证。迁移到.NET5.0我想利用这种基于资源的授权的授权框架,但我不想在每个控制器中重复这种逻辑。我的解决方案是实现一个执行类似操作的授权处理程序,获取siteId参数并验证用户的访问权限:_logger=logger.NotNull(nameof(logger));}protectedoverrideTaskHandleRequirementAsync(AuthorizationHandlerContextcontext,SiteAccessRequirementrequirement){context.NotNull(nameof(context));requirement.NotNull(nameof(requirement));if(context.ResourceisHttpContext.httpContexthttpContext&Data&Route&Data()。Values.TryGetValue(SiteIdRouteParameter,outobject?routeValue)&&routeValueisstringsiteId){stringqualifiedId=$"sites/{siteId}";AccountPrincipalaccount=context.User.ToAccount();_logger.LogDebug("ValidatingaccesstoSite{SiteId}fromUser{UserId}.",qualifiedId,account.GetAuthIdentifier());if(account.CanAccessSite(qualifiedId)){context.Succeed(requirement);}else{_logger.LogWarning("Sitevalidationfailed.User{UserId}isnotpermittedtoaccess{SiteId}.",account.GetAuthIdentifier(),qualifiedId);}}returnTask.CompletedTask;}}然后将其注册为授权策略的一部分:services.AddAuthorization(options=>{options.FallbackPolicy=Policies.FallbackPolicy;options.AddPolicy("SiteAccess",Policies.SiteAccessPolicy);})publicstaticAuthorizationPolicySiteAccessPolicy=>ConfigureDefaults(newAuthorizationPolicyBuilder()).AddRequirements(newSiteAccessRequirement()).Build();privatestaticAuthorizationPolicyBuilderConfigureDefaults(AuthorizationPolicyBuilderbuilder)=>builder.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser().RequiretClaim(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser().RequiretClaim(JwtClaim)对于控制器和/或操作:[Authorize(Policy="SiteAccess")][HttpGet("{siteId}",Name=RouteNames.SiteRoute)]publicasyncTask
