【问题标题】:UnauthorizedAccessException behavior in ASP.NET Core policy based authorization基于 ASP.NET Core 策略的授权中的 UnauthorizedAccessException 行为
【发布时间】:2021-11-07 18:46:53
【问题描述】:

我有一个简单的 ASP.NET Core API (.net 5) 应用程序,其安全配置如下:

    services.AddControllers(options =>
        options.Filters.Add(new MyExceptionFilter()));
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)     
       .AddMicrosoftIdentityWebApi(Configuration.GetSection("AAD"));

    services.AddAuthorization(options =>
    {
        options.AddPolicy("MyPolicy", policy =>
           policy.RequireAssertion(context =>
               context.User.HasClaim(c => c.Type == "myclaim" && c.Value == "myvalue")));
    });

然后将策略应用于控制器:

    [ApiController]
    [Route("[controller]")]
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Policy = "MyPolicy")]
    public class DefaultController : ControllerBase {}

当令牌没有必需的声明时,框架会抛出 System.UnauthorizedAccessException

System.UnauthorizedAccessException: IDW10201: Neither scope or roles claim was found in the bearer token. 
   at Microsoft.Identity.Web.MicrosoftIdentityWebApiAuthenticationBuilderExtensions.<>c__DisplayClass3_1.<<AddMicrosoftIdentityWebApiImplementation>b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

没关系。不好的是它随后转换为 HTTP 500,尽管我期望 HTTP 403。问题是标准异常过滤器(继承自 Microsoft.AspNetCore.Mvc.Filters.ExceptionFilterAttribute)没有捕捉到它,可能是因为它在管道中发生得太早了。

为什么要这样设计?如何将身份验证阶段的异常映射到我需要的任何内容?

【问题讨论】:

  • 你能显示你的AddJwtBearer 步骤吗?异常是在AuthenticationMiddleware 上抛出的,它甚至没有到达AuthorizationMiddleware,授权策略还没有发生......有点奇怪
  • @GordonKhanhNg。更新代码,谢谢。

标签: c# asp.net-core asp.net-web-api error-handling .net-5


【解决方案1】:

好的...我明白了。感谢更新代码,没有它就无法追溯这么深。

代码使用AddMicrosoftIdentityWebApi,属于Microsoft.Identity.Web包。在屏幕后面,使用JwtBearerOptionsJwtBearerHandler

AddMicrosoftIdentityWebApi 的配置中,JwtBearerEvents 是要求范围和角色声明的硬代码,如您所见here

http://schemas.microsoft.com/identity/claims/scopehttp://schemas.microsoft.com/ws/2008/06/identity/claims/role 专用于 .net 世界,scproles 用于 Oauth 标准世界。 Jwt 令牌输入的内容必须至少具有这四个范围中的一个,否则,将引发异常(如 JwtBearerEvents 调用以验证 here,它直接指向 here,它被硬编码为上面的第一个链接。)

关键是,异常会在AuthenticationMiddleware 上抛出,这在我们的管道中非常高,在此处捕获UnauthorizedAccessException 以返回 403 可能会吞噬任何使用我们想要抛出的UnauthorizedAccessException 的自定义逻辑应用程序逻辑(就我而言,我在自己的项目中使用了这种异常)。

因此,最合适的方法是确保 jwt 令牌输入具有我上面提到的四个范围之一(Microsoft.Identity.Web 包本身需要它)。或者使用位于AuthenticationMiddleware 上方的中间件,仅在消息包含IDW10201 时捕获UnauthorizedAccessException 异常,然后将响应从500 写回403。(我仍然更喜欢Controller 级别以下的异常过滤器,因为我可以分离哪个异常来自我的逻辑,或来自其他地方)。

【讨论】:

    最近更新 更多