如何在ASP.NET Core 3.1 API中配置多授权方式?
我运行着一个基于ASP.NET Core 3.1的API,当前使用JWT Bearer令牌(由OAuth2提供商颁发)正常工作,默认授权策略已配置并启用RequireAuthenticatedUser()。现在需要给部分端点配置另一种授权流程,于是创建了自定义AuthorizationHandler并绑定到对应策略,绑定到目标端点后,自定义Handler确实触发了,而且已经调用context.Succeed(requirement)并返回Task.CompletedTask,但仍然收到401未授权响应,求排查问题。
自定义Handler代码:
public class MyCustomAuthorizeRequirement : IAuthorizationRequirement { } public class MyCustomAuthorizeRequirementHandler : AuthorizationHandler<MyCustomAuthorizeRequirement>, IAuthorizationRequirement { private readonly MyCustomSettings _MyCustomSettings; public MyCustomAuthorizeRequirementHandler(MyCustomSettings MyCustomSettings) { _MyCustomSettings = MyCustomSettings; } protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyCustomAuthorizeRequirement requirement) { var httpContext = context.Resource as HttpContext; string authHeader = httpContext.Request.Headers["Authorization"]; if (authHeader != null && authHeader.StartsWith("x-auth-")) { if(authHeader != _MyCustomSettings.MyCustomAuthKey) { context.Fail(); return Task.CompletedTask; } } context.Succeed(requirement); return Task.CompletedTask; } }
Program.cs相关代码片段:
builder.Services .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(); // Configure policies builder.Services .AddAuthorization(options => { var userAuthPolicyBuilder = new AuthorizationPolicyBuilder(); options.DefaultPolicy = userAuthPolicyBuilder .RequireAuthenticatedUser() .Build(); options.AddPolicy("MyCustomAuthorize", policy => policy.Requirements.Add(new MyCustomAuthorizeRequirement())); }); MyCustomSettings localMyCustomSettings = new MyCustomSettings(); configuration.GetSection("MyCustomSettings").Bind(localMyCustomSettings); builder.Services.AddSingleton<IAuthorizationHandler>(new MyCustomAuthorizeRequirementHandler(localMyCustomSettings));
1. 自定义Handler错误实现IAuthorizationRequirement
MyCustomAuthorizeRequirementHandler同时继承AuthorizationHandler<MyCustomAuthorizeRequirement>和实现IAuthorizationRequirement是错误的。IAuthorizationRequirement是授权要求的标记接口,Handler是处理要求的逻辑类,不需要实现该接口。这个错误会让授权系统把Handler当成额外的未处理要求,最终导致授权失败。
2. 自定义策略未脱离默认认证约束
默认策略要求RequireAuthenticatedUser(),但自定义策略仅添加了自定义要求,未明确跳过默认的JWT认证检查。当请求使用自定义x-auth-头时,JWT认证中间件会因找不到有效令牌标记用户为未认证,即便自定义Handler通过,最终仍会因默认认证要求未满足返回401。
3. 自定义Handler逻辑存在漏洞
当前逻辑中,若Authorization头不以x-auth-开头,会直接调用context.Succeed(requirement),导致未携带正确头的请求也能通过自定义策略,但结合默认认证仍会失败;同时需明确所有分支的授权结果,避免逻辑遗漏。
修正自定义Handler
public class MyCustomAuthorizeRequirement : IAuthorizationRequirement { } // 移除IAuthorizationRequirement接口实现 public class MyCustomAuthorizeRequirementHandler : AuthorizationHandler<MyCustomAuthorizeRequirement> { private readonly MyCustomSettings _myCustomSettings; public MyCustomAuthorizeRequirementHandler(MyCustomSettings myCustomSettings) { _myCustomSettings = myCustomSettings; } protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyCustomAuthorizeRequirement requirement) { var httpContext = context.Resource as HttpContext; string authHeader = httpContext.Request.Headers["Authorization"]; if (authHeader != null && authHeader.StartsWith("x-auth-")) { if (authHeader == _myCustomSettings.MyCustomAuthKey) { context.Succeed(requirement); return Task.CompletedTask; } context.Fail(); return Task.CompletedTask; } // 未携带正确自定义头,直接拒绝 context.Fail(); return Task.CompletedTask; } }
修正Program.cs授权策略配置
builder.Services .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(); // 配置授权策略 builder.Services .AddAuthorization(options => { // 默认策略:要求JWT认证 options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme) .RequireAuthenticatedUser() .Build(); // 自定义策略:仅使用自定义授权逻辑,不依赖默认认证要求 options.AddPolicy("MyCustomAuthorize", policy => { policy.Requirements.Add(new MyCustomAuthorizeRequirement()); }); }); // 注册自定义Handler(泛型方式更简洁) MyCustomSettings localMyCustomSettings = new MyCustomSettings(); configuration.GetSection("MyCustomSettings").Bind(localMyCustomSettings); builder.Services.AddSingleton<IAuthorizationHandler, MyCustomAuthorizeRequirementHandler>(sp => new MyCustomAuthorizeRequirementHandler(localMyCustomSettings));
端点绑定自定义策略
确保目标端点使用自定义策略,而非默认授权:
[ApiController] [Route("api/custom")] public class CustomController : ControllerBase { [HttpGet] [Authorize(Policy = "MyCustomAuthorize")] public IActionResult Get() { return Ok("Custom authorized access"); } }
内容的提问来源于stack exchange,提问作者Stephen Cossgrove

