【问题标题】:ASP.NET Core 2.0 JWT Validation fails with `Authorization failed for user: (null)` errorASP.NET Core 2.0 JWT 验证失败并出现“用户授权失败:(null)”错误
【发布时间】:2018-01-30 03:51:40
【问题描述】:

我使用 ASP.NET Core 2.0 应用程序 (Web API) 作为 JWT 颁发者来生成移动应用程序可使用的令牌。不幸的是,这个令牌不能被一个控制器验证,而可以被另一个控制器验证(在同一个 asp.net core 2.0 应用程序中使用相同的验证设置)。

所以我有一个有效且可以解码的令牌,具有所有必需的声明和时间戳。但是一个端点接受它,而另一个给我 401 错误和调试输出:

Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:信息: 用户授权失败:(null)。

[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed for user: (null).
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed for user: (null).
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
      Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes ().
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
      Executing ChallengeResult with authentication schemes ().
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12]
      AuthenticationScheme: Bearer was challenged.
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: AuthenticationScheme: Bearer was challenged.
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action MyController.Get (WebApi) in 72.105ms
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action MyController.Get (WebApi) in 72.105ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 271.077ms 401 
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 271.077ms 401 

我的验证设置如下:

var secretKey = Configuration["Authentication:OAuth:IssuerSigningKey"];
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
var tokenValidationParameters = new TokenValidationParameters
{
   ValidateIssuerSigningKey = true,
   IssuerSigningKey = signingKey,
   ValidateIssuer = true,
   ValidIssuer = Configuration["Authentication:OAuth:Issuer"],
   ValidateAudience = true,
   ValidAudience = Configuration["Authentication:OAuth:Audience"],
   ValidateLifetime = true,
   ClockSkew = TimeSpan.Zero,
};

services.AddAuthentication(options =>
{
   options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
   options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
   options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
    options.RequireHttpsMetadata = false;
    options.TokenValidationParameters = tokenValidationParameters;
});

这两个端点是相同的,只是存在于不同的控制器中,都标有Authorize 属性。

这怎么可能?

【问题讨论】:

  • +1 您的详细代码引起了我对ClockSkew 的注意,这让我了解了一个单独的问题,即我的令牌似乎没有过期。

标签: c# asp.net-core asp.net-core-webapi bearer-token asp.net-core-identity


【解决方案1】:

你可以试试这个:

.AddJwtBearer(options =>
{
    options.RequireHttpsMetadata = false;
    options.TokenValidationParameters = tokenValidationParameters;
});'

【讨论】:

  • 很确定这行不通。从核心 2.0 开始,“AutomaticAuthenticate”和“AutomaticChallenge”已从 JwtBearerOptions 中移除。在这里阅读:docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/…
  • 是的,它已被删除,现在被defaultAuthenticateSchemedefaultChallengeScheme 替换。
【解决方案2】:

在 startup.cs 中试试这个

services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(opts => ...

【讨论】:

    【解决方案3】:

    我补充说:

    app.UseAuthentication();
    

    Startup.Configure() 中为我解决了这个错误。

    参考:Auth 2.0 Migration announcement

    【讨论】:

      【解决方案4】:

      configure 函数中添加语句的顺序很重要。确保

      app.UseAuthentication();
      

      先于

      app.UseMvc();
      

      这可能是问题所在?

      【讨论】:

      • 在我的例子中,对使用 Authorize 属性修饰的操作的初始请求会成功,然后任何后续请求都会失败。这解决了我的问题。
      • 我不好意思说我错过了 app.UseAuthentication();完全!
      • 忘记订单,我完全忘了把 app.UseAthentication() 部分。谢谢,Ole。
      • 我知道顺序很重要,但我仍然不认为身份验证必须在 MVC 之前进行......duh。谢谢!
      • 谁能解释一下为什么订单很重要。
      【解决方案5】:

      这似乎是您在未正确验证您的 JWT 时收到的行为。由于在标题中输入“Bearer:(JWT)”而不是“Bearer(JWT)”,我遇到了这个问题

      【讨论】:

      • 谢谢。我正在使用 swagger 来测试我的端点并且面临这个身份验证错误。您的评论使我走上了正确的道路来整理我的招摇定义,以便正确传递令牌。 (就我而言,它缺少“承载者”)
      【解决方案6】:

      在你的 startup.cs ConfigureServices 方法中添加

      services.AddAuthentication(options =>
                  {
                      options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                  }).AddJwtBearer(options => ...
      

      解释: 当您在控制器上使用 [Authorize] 时,它默认绑定到第一个授权系统。

      options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
      

      这样,您将默认设置为 JWT Bearer 身份验证。

      另外你可以添加

      options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
      

      这一行是如何防止在将 Identity 与 JWT 结合使用时出现 404 not found 错误。如果您使用身份,DefaultChallengeScheme 将尝试将您重定向到登录页面,如果不存在将导致 404 未找到而不是所需的 401 未经授权。通过在未经授权的情况下将 DefaultChallengeScheme 设置为 JwtBearerDefaults.AuthenticationScheme,它将不再尝试将您重定向到登录页面

      如果您在 [Authorize] 标记中使用带有 JWT 身份验证的 Cookie 身份验证,您可以指定您想要的身份验证方案。例如

      [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
      

      【讨论】:

      【解决方案7】:

      当添加身份验证时:

        services.AddAuthentication(options => {
                  options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                  options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                  options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
              })
              ....
      

      这意味着放置在方法或控制器类之上的每个属性 [Authorize] 将尝试根据默认身份验证模式(在本例中为 JwtBearer)进行身份验证并且它不会级联 尝试使用可能声明的其他模式(如 Cookie 模式)进行身份验证。为了使 AuthorizeAttribute 针对 cookie 模式进行身份验证,必须像

      一样指定它
      [Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
      

      这也可以反过来工作,即如果 cookie 模式是默认的,则必须声明 JwtBearer 模式以授权那些需要 JwtBearer 令牌身份验证的方法或控制器

      [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
      

      【讨论】:

        【解决方案8】:

        检查令牌提供程序中的签名密钥编码,例如它可以是 UTF8 而不是 ASCII。

        【讨论】:

          【解决方案9】:

          对于 Dotnetcore 3.1,我将 app.UseAuthentication() 放在 app.UseAuthorization() 之前

          【讨论】:

          • 如果我能给这个 1000 upvotes 我会的。如果需要对这些东西下订单,您会认为会有警告
          【解决方案10】:

          对于使用.NET Core 3.1 的任何人,它是这样工作的:

          public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
          {
              if (env.IsDevelopment())
              {
                  app.UseDeveloperExceptionPage();
              }
          
              app.UseCors("AllowOrigin");
              app.UseHttpsRedirection();
              app.UseRouting();
              app.UseAuthentication();
              app.UseAuthorization();
              app.UseEndpoints(endpoints =>
              {
                  endpoints.MapControllers();
              });
          }
          

          【讨论】:

            【解决方案11】:

            如果有人对IServiceCollection.AddAuthentication 的配置或Startup.Configure 的实现没有任何答案,您可以尝试更改IServiceCollection.AddAuthorization 的配置。

            在进行此更改之前,使用正确令牌调用 API 失败并显示以下日志行。

            [Information] [Microsoft.AspNetCore.Hosting.Diagnostics] Request starting HTTP/1.1 POST http://localhost:5000/api application/json 18
            [Debug] [Microsoft.AspNetCore.Routing.Matching.DfaMatcher] 1 candidate(s) found for the request path '"/api"'
            [Debug] [Microsoft.AspNetCore.Routing.Matching.DfaMatcher] Endpoint '"ApplicationNamespace.Controllers.ApiController.CreateAsync (ApplicationNamespace)"' with route pattern '"Api"' is valid for the request path '"/api"'
            [Debug] [Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware] Request matched endpoint '"ApplicationNamespace.Controllers.ApiController.CreateAsync (ApplicationNamespace)"'
            [Debug] [Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler] AuthenticationScheme: "Identity.Application" was not authenticated.
            [Debug] [Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler] AuthenticationScheme: "Identity.Application" was not authenticated.
            [Information] [Microsoft.AspNetCore.Authorization.DefaultAuthorizationService] Authorization failed.
            [Information] [Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler] Successfully validated the token.
            [Information] [Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler] AuthenticationScheme: "Bearer" was challenged.
            [Information] [Serilog.AspNetCore.RequestLoggingMiddleware] HTTP "POST" "/api" responded 401 in 4.6311 ms
            

            Startup.ConfigureServices 中,一旦我应用了指定身份验证方案的默认策略,它就对我有用。

            services.AddAuthorization(opt =>
              {
                var builder = new AuthorizationPolicyBuilder();
                builder.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
                builder.RequireAuthenticatedUser();
                opt.DefaultPolicy = builder.Build();
              });
            

            【讨论】:

              猜你喜欢
              • 2018-08-25
              • 2018-03-12
              • 1970-01-01
              • 1970-01-01
              • 2017-10-15
              • 2021-06-25
              • 2014-11-19
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多