ASP.NET Core 2.0 JWT验证因“用户授权失败:(null)”错误而失败

时间:2017-08-22 01:56:34

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

我正在使用ASP.NET Core 2.0应用程序(Web API)作为JWT颁发者来生成移动应用程序的令牌消费品。不幸的是,这个令牌无法由一个控制器验证,而另一个控制器可以验证(在同一个asp.net核心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属性。

这怎么可能?

11 个答案:

答案 0 :(得分:68)

configure函数中add语句的顺序非常重要。确保

app.UseAuthentication();

之前

app.UseMvc();

这可能是问题吗?

答案 1 :(得分:20)

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

答案 2 :(得分:11)

如果添加

,则在您的startup.cs ConfigureServices方法中
services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options => ...

说明: 在控制器上使用 [授权] 时,它默认绑定到第一个授权系统。

options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;

使用此功能,您将默认设置为JWT Bearer身份验证。

另外你可以添加

options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

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

如果您在 [授权] 标记中使用带有JWT身份验证的Cookie身份验证,则可以指定所需的authenticationScheme。例如

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

答案 3 :(得分:8)

对于使用.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();
    });
}

答案 4 :(得分:6)

我补充说:

app.UseAuthentication();

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

参考:Auth 2.0 Migration announcement

答案 5 :(得分:2)

在startup.cs中尝试这个

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

答案 6 :(得分:1)

如果任何人对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();
  });

答案 7 :(得分:0)

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

答案 8 :(得分:0)

添加身份验证后,如:

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

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

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

反之亦然,也就是说,如果cookie模式是默认模式,则必须声明JwtBearer模式以授权那些需要JwtBearer令牌认证的方法或控制器

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

答案 9 :(得分:0)

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

答案 10 :(得分:-2)

你可以试试这个:

.AddJwtBearer(options =>
{
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    options.RequireHttpsMetadata = false;
    options.TokenValidationParameters = tokenValidationParameters;
});'