.NET核心Web API、JWT和Swagger - 401显示为“未记录”,而不是“未授权”

0mkxixxg  于 2022-11-06  发布在  .NET
关注(0)|答案(4)|浏览(301)

我有一个ASP.NETCoreWebAPI3应用程序,它实现了一个RESTAPI,并使用一个JWT不记名令牌进行授权,还有Swagger(Swashbuckle)。
我的控制器上有[授权]过滤器,例如:

[ApiController]
[Route("api/[controller]")]
[Authorize]
public class MyController : ControllerBase
{
}

Swagger可以使用我的API,我可以生成一个JWT标记并将其提供给Swagger,一切都运行良好。
但是,如果我尝试使用Swagger在没有JWT标记或无效的JWT标记的情况下访问我的一个REST端点,Swagger UI将显示错误401Undocumented,但我在Web上看到的所有示例都显示我应该得到401Unauthorized
(When我点击了与 Postman 相同的URL,它确实显示401未经授权。)
在我开始撕东西之前,你知道为什么我可能会得到无证而不是未经授权吗?
这就是我看到的:

当我添加下面建议的属性

(ProducesResponseType(typeof(ProblemDetails), (int)HttpStatusCode.Unauthorized)])

我看到的是:

aoyhnmkz

aoyhnmkz1#

您可以在Startup.cs中添加应用程序.UseStatusCodePages()。
这将返回响应主体

bxgwgixi

bxgwgixi2#

请尝试在action方法中使用以下属性,

[ProducesResponseType(typeof(ProblemDetails), (int)HttpStatusCode.Unauthorized)]
bqucvtff

bqucvtff3#

也许是晚了,但我是进入这个问题,所以现在我会回答。
它显示Undocumented是因为Authorization头的开头没有bearer关键字。你的头可能是这样的:

Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJNb3N0YWZhOTEiLCJqdGkiOiIzNGEzNjQwNC1iZWNjLTRhMmMtOGJkZi01ZDc1ZTBiY2QwZGIiLCJJZCI6IjEiLCJleHAiOjE2MTAyNDcyMTUsImlzcyI6Im1vaGFtYWRyYXZhZWkuaW5mbyIsImF1ZCI6Im1vaGFtYWRyYXZhZWkuaW5mbyJ9.0_kKI7F12o62A_QUZ38U9KVbBpnQMyO7kGcqBZzU4AU

因此应将其更改为:

Authorization: 
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJNb3N0YWZhOTEiLCJqdGkiOiIzNGEzNjQwNC1iZWNjLTRhMmMtOGJkZi01ZDc1ZTBiY2QwZGIiLCJJZCI6IjEiLCJleHAiOjE2MTAyNDcyMTUsImlzcyI6Im1vaGFtYWRyYXZhZWkuaW5mbyIsImF1ZCI6Im1vaGFtYWRyYXZhZWkuaW5mbyJ9.0_kKI7F12o62A_QUZ38U9KVbBpnQMyO7kGcqBZzU4AU

实际上, Postman 在令牌的开头设置了bearer,如果您设置了Bearer,但令牌被弃用,则状态代码将显示为未授权代码。

eyh26e7m

eyh26e7m4#

你知道为什么我会得到“无证”而不是“未经授权”吗
因为它没有被Swashbuckle记录下来。
基本上有两种选择:
选项一:在每个[授权]端点上使用XML注解,下面是一个示例:

/// <summary>
/// StackOverflow example
/// </summary>
/// <response code="200">All good here</response>
/// <response code="401">Unauthorized</response>
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class MyController : ControllerBase
{

}

并实现来自XML注解的Include描述,如下所示。
选项二:使用操作筛选器一次以将其添加到所有[已授权]端点:
创建新类:

// using Microsoft.AspNetCore.Authorization;
// using Microsoft.OpenApi.Models;
// using Swashbuckle.AspNetCore.SwaggerGen;
public class AuthResponsesOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (context != default && context.MethodInfo != default && context.MethodInfo.DeclaringType != default)
        {
            IEnumerable<AuthorizeAttribute> authAttributes = context.MethodInfo.DeclaringType.GetCustomAttributes(true)
                .Union(context.MethodInfo.GetCustomAttributes(true))
                .OfType<AuthorizeAttribute>();

            if (authAttributes.Any() && !operation.Responses.Any(r => r.Key == "401"))
                operation.Responses.Add("401", new OpenApiResponse { Description = "User not authenticated." });

            // if (authAttributes.Any() && !operation.Responses.Any(r => r.Key == "403"))
            //     operation.Responses.Add("403", new OpenApiResponse { Description = "User not authorized to access this endpoint." });
        }
    }
}

并在Program.cs文件中设置它(ASP.NET6+):

builder.Services.AddSwaggerGen(c =>
{
    c.OperationFilter<AuthResponsesOperationFilter>();
};

或Startup.cs文件(ASP.NET 5)中的一个或多个文件:

services.AddSwaggerGen(c =>
{
    c.OperationFilter<AuthResponsesOperationFilter>();
};

请参阅此处了解更多详情:螺旋扣操作filters

相关问题