UseJwtBearerAuthentication 在令牌到期时返回 HTTP 500

UseJwtBearerAuthentication returning HTTP 500 on token expiry

我正在这样使用 UseJwtBearerAuthentication

app.UseJwtBearerAuthentication(options =>
{
   options.Authority = Configuration["Urls:IdentityServer"];
   options.RequireHttpsMetadata = false;

   options.Audience = Configuration["Urls:IdentityServer"] + "/resources";
   options.AutomaticAuthenticate = true;
   options.Events = new JwtBearerEvents
   {
        OnAuthenticationFailed = context =>
        {
          context.HandleResponse();   
          return Task.FromResult(0);
        }
   }; 
});

在 visual studio 的诊断 window 中,我看到了这两个异常:

System.IdentityModel.Tokens.SecurityTokenExpiredException' in System.IdentityModel.Tokens.dll ("IDX10223: Lifetime validation failed. The token is expired.

并沿线

Exception thrown: 'System.ArgumentNullException' in Microsoft.AspNet.Authentication.dll ("Value cannot be null.")

如何返回 HTTP 401 Unauthorized?

这是一个known bug. Sadly, no longer works in RC1

您唯一的选择是编写一个捕获异常的中间件,以防止服务器返回 500 响应。当然,它很丑陋并且可能会隐藏重要的异常,但它是唯一已知的适用于 RC1 的解决方法。

这是一个例子:

app.Use(next => async context =>
{
    try
    {
        await next(context);
    }

    catch
    {
        // If the headers have already been sent, you can't replace the status code.
        // In this case, re-throw the exception to close the connection.
        if (context.Response.HasStarted)
        {
            throw;
        }

        // Rethrow the exception if it was not caused by IdentityModel.
        if (!context.Items.ContainsKey("jwt-workaround"))
        {
            throw;
        }

        context.Response.StatusCode = 401;
    }
});

app.UseJwtBearerAuthentication(new JwtBearerOptions
{
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    RequireHttpsMetadata = false,

    Audience = "http://localhost:54540/",
    Authority = "http://localhost:54540/",

    Events = new JwtBearerEvents
    {
        OnAuthenticationFailed = context =>
        {
            context.HttpContext.Items["jwt-workaround"] = null;

            return Task.FromResult(0);
        }
    };
});