ASP.NET Core基于策略授权的UnauthorizedAccessException异常处理问题
设计原因
- ASP.NET Core 请求管道是按注册顺序执行的,你定义的
ExceptionFilter属于MVC过滤器范畴,仅当请求进入MVC中间件处理流程后才会生效。而认证异常抛出在AuthenticationMiddleware(认证中间件)阶段,该中间件默认注册在MVC中间件之前,异常触发时请求还未进入MVC管道,因此过滤器无法捕获。 - 你遇到的
IDW10201异常是Microsoft.Identity.Web库的默认校验逻辑抛出的:该库默认要求访问API的令牌必须携带scope或roles声明,校验不通过直接抛出未处理异常,未处理的管道异常默认会被转换为HTTP 500状态码。
解决方案
以下三个方案按推荐优先级排序:
方案1:关闭默认scope/roles校验,走自定义授权逻辑
这是最贴合你需求的方案,关闭库的默认校验后,请求会直接进入你定义的MyPolicy授权策略校验,校验不通过默认返回403状态码:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi( jwtOptions => { Configuration.Bind("AAD", jwtOptions); // 关闭默认的scope/roles强制校验 jwtOptions.AllowWebApiToBeAuthorizedByACL = true; }, msIdentityOptions => Configuration.Bind("AAD", msIdentityOptions) );
方案2:自定义全局异常处理中间件
如果需要捕获所有管道阶段的异常做统一映射,可以在管道最开头注册自定义中间件:
第一步:实现中间件逻辑
public class AuthExceptionHandlerMiddleware { private readonly RequestDelegate _next; public AuthExceptionHandlerMiddleware(RequestDelegate next) => _next = next; public async Task InvokeAsync(HttpContext context) { try { await _next(context); } catch (UnauthorizedAccessException ex) when (ex.Message.Contains("IDW10201")) { context.Response.StatusCode = StatusCodes.Status403Forbidden; context.Response.ContentType = "application/json"; await context.Response.WriteAsJsonAsync(new { Code = 403, Message = "令牌缺少必要的访问声明" }); } } }
第二步:注册中间件到管道最顶端
在Startup.cs的Configure方法中,将该中间件放在所有其他中间件之前:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // 第一个注册 app.UseMiddleware<AuthExceptionHandlerMiddleware>(); // 后面再注册其他中间件,如异常页、认证、授权、路由、MVC等 // ... }
方案3:定制JwtBearer认证事件
直接在认证组件的事件中处理异常,避免异常向上抛出:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi( jwtOptions => { Configuration.Bind("AAD", jwtOptions); jwtOptions.Events = new JwtBearerEvents { OnAuthenticationFailed = context => { if (context.Exception is UnauthorizedAccessException && context.Exception.Message.Contains("IDW10201")) { context.Response.StatusCode = StatusCodes.Status403Forbidden; context.ExceptionHandled = true; } return Task.CompletedTask; } }; }, msIdentityOptions => Configuration.Bind("AAD", msIdentityOptions) );
内容的提问来源于stack exchange,提问作者UserControl
相关产品推荐
相关产品推荐

