【问题标题】:.NET Core 2.2 JWT Token authorization failure not returning HTTP 401.NET Core 2.2 JWT 令牌授权失败未返回 HTTP 401
【发布时间】:2019-06-05 20:00:11
【问题描述】:

我遇到了 .NET Core 如何在我的生产环境中处理 JSON Web Token (JWT) 身份验证的问题。我正在使用 Postman 进行测试。如果我使用有效令牌调用我的 API,它可以正常工作并从 API 端点返回预期的响应。但是,如果令牌过期,我不会得到预期的 HTTP 401。事实上,我没有得到任何响应,它只是悄悄地失败了。这似乎是我的生产配置不起作用。如果我在本地开发环境中对此进行测试,我没有任何问题,并且过期的令牌会像预期的那样得到 401 未授权的 HTTP 响应。

我的网络应用对通过网站登录的用户使用 cookie 身份验证,对连接到 API 的用户使用 JWT 身份验证。这是 JWT 身份验证的配置。这是在 Startup.cs 中。这是 services.Authentication 的 JWT 配置部分。 cookie 身份验证是首先设置的,是默认的身份验证方案。

.AddJwtBearer(options =>{
options.RequireHttpsMetadata = !_hostingEnvironment.IsDevelopment();

options.TokenValidationParameters = new TokenValidationParameters
{
    ValidateIssuer = true,
    ValidateAudience = true,
    ValidateLifetime = true,
    ValidateIssuerSigningKey = true,

    ValidIssuer = Settings.Api.JwtBearer.TokenValidation.ValidIssuer,
    ValidAudience = Settings.Api.JwtBearer.TokenValidation.ValidAudience,
    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Settings.Api.JwtBearer.TokenValidation.IssuerSigningKey))
};

options.Events = new JwtBearerEvents()
{
    OnAuthenticationFailed = context =>
    {
        context.Response.StatusCode = StatusCodes.Status401Unauthorized;
        context.Response.ContentType = "application/json; charset=utf-8";
        var message = _hostingEnvironment.IsDevelopment() ? context.Exception.ToString() : "An error occurred processing your authentication.";
        var result = JsonConvert.SerializeObject(new { message });
        return context.Response.WriteAsync(result);
    }
};});

这里是 Startup.cs 中的其他相关配置:

public void Configure(IApplicationBuilder app, IHostingEnvironment env){
if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error/Exception");

    app.UseStatusCodePagesWithReExecute("/Error/{0}");

    app.UseHsts();

    app.UseHttpsRedirection();
}

app.UseStaticFiles();

app.UseCors(Constants.Security.Cors.PolicyName);

app.UseAuthentication();

app.UseMvc(ConfigureRoutes);}

` 我已经使用了很多配置设置并在生产中进行了测试,但是当令牌身份验证失败时,我总是没有得到任何响应。由于它在我的本地开发环境中运行良好,这一定意味着我的生产配置有问题,但我被难住了,没有想法。有关更多信息,这里是错误日志中的错误示例:

信息: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[1] 无法验证令牌。 Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException: IDX10223:生命周期验证失败。令牌已过期。有效: '[PII 已隐藏]',当前时间:'[PII 已隐藏]'。在 Microsoft.IdentityModel.Tokens.Validators.ValidateLifetime(Nullable1 notBefore, Nullable1 过期, SecurityToken securityToken, TokenValidationParameters 验证参数)在 System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateLifetime(Nullable1 notBefore, Nullable1 过期, JwtSecurityToken jwtToken, TokenValidationParameters 验证参数)在 System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters 验证参数)在 System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(字符串 令牌、TokenValidationParameters 验证参数、SecurityToken& 验证令牌)在 Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.d__6.MoveNext() 信息: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[7] 承载未通过身份验证。失败消息:IDX10223:生命周期验证失败。令牌已过期。 ValidTo: '[PII 是 hidden]', 当前时间:'[PII is hidden]'。信息: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] 授权失败。信息:Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3] 过滤器“Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter”处的请求授权失败。信息: Microsoft.AspNetCore.Mvc.ChallengeResult[1] 使用身份验证方案(承载)执行 ChallengeResult。信息:Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] 在 109.4625 毫秒内执行操作 Web.Controllers.ApiController.Users (Web) 信息:Microsoft.AspNetCore.Routing.EndpointMiddleware[1] 执行端点“Web.Controllers.ApiController.Users (Web)”失败:Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1] 执行请求时发生未处理的异常。 System.InvalidOperationException:无法设置 StatusCode,因为 响应已经开始。在 Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.set_StatusCode(Int32 值)在 Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.Microsoft.AspNetCore.Http.Features.IHttpResponseFeature.set_StatusCode(Int32 值)在 Microsoft.AspNetCore.Http.Internal.DefaultHttpResponse.set_StatusCode(Int32 值)在 Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.d__7.MoveNext()

提前感谢您提供有关如何解决此问题的任何想法。

【问题讨论】:

  • 这是您的错误:失败:Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1] 执行请求时发生未处理的异常。 System.InvalidOperationException:无法设置 StatusCode,因为响应已经开始。
  • 我只有在覆盖响应的状态码时才会发生这种情况,换句话说,当通过中间件放置响应并且该中间件更改了响应的状态码时,您会收到此错误。希望这能帮助您找到问题。
  • 是的,这似乎是问题所在。但是,我仍然存在如何使用 401 返回自定义错误消息的问题。

标签: authentication asp.net-core jwt http-status-code-401


【解决方案1】:

所以我找到了一个部分解决方案,至少可以解除对我的阻碍,这样我就可以继续我的 API 开发。尝试更改 JwtBearerEvents OnAuthenticationFailed 中的 context.Response 在我的生产环境中不起作用(尽管它在我的本地计算机上工作正常)。我尝试了很多变体,但最后唯一有效的方法是从 Startup.cs 中删除整个代码块:

options.Events = new JwtBearerEvents()
{
    OnAuthenticationFailed = context =>
    {
        context.Response.StatusCode = StatusCodes.Status401Unauthorized;
        context.Response.ContentType = "application/json; charset=utf-8";
        var message = _hostingEnvironment.IsDevelopment() ? context.Exception.ToString() : "An error occurred processing your authentication.";
        var result = JsonConvert.SerializeObject(new { message });
        return context.Response.WriteAsync(result);
    }
};

一旦我这样做了,我就开始在 Postman 中进行测试时收到 401 代码表示令牌验证失败,这是一件好事,也是预期的行为。然而,在响应的正文中,默认的错误页面 HTML 也被返回。

为了解决这个问题,我不得不修改 Startup.cs 中的 Configure 方法,以便 UseStatusCodePagesWithReExecute 忽略 API:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error/Exception");

        app.UseWhen(context => !context.Request.Path.Value.StartsWith("/api"), builder =>
        {
            builder.UseStatusCodePagesWithReExecute("/Error/{0}");
        });

        app.UseHsts();

        app.UseHttpsRedirection();
    }

    app.UseStaticFiles();

    app.UseCors(Constants.Security.Cors.PolicyName);

    app.UseAuthentication();

    app.UseMvc(ConfigureRoutes);
}

这行得通,但我不喜欢它。感觉就像一个黑客。现在我得到了令牌身份验证失败的 401 并且正文中没有任何内容。就像我之前提到的那样,这可以解除对我的阻止,但我仍然希望使用响应返回自定义错误消息。

那么,我的下一个问题是,如果我不能使用 JwtBearerEvents OnAuthenticationFailed 添加消息,那么在哪里添加错误消息的正确位置?

【讨论】:

猜你喜欢
  • 2020-03-28
  • 2020-05-05
  • 2019-06-26
  • 2018-04-22
  • 2017-08-22
  • 2017-11-12
  • 2020-02-27
  • 2019-01-04
  • 1970-01-01
相关资源
最近更新 更多