ASP.NET 核心 API:Swagger 中未显示身份验证弹出窗口 UI

ASP.NET Core API: Authentication popup is not showing up in Swagger UI

我有一个 ASP.NET Core Web API,它使用 Swashbuckle 集成了 Swagger。我已经使用操作过滤器在 Swagger UI 上成功集成了授权,因为我不想显示匿名 APIs 的挂锁。

.OperationFilter<AuthorizeFilter>()

在过滤器内部,我已经注册了 Swagger 的基本身份验证安全要求 UI。

我的问题是,即使在 API 秒内在 Swagger UI 上进行身份验证,我也不再看到单击挂锁图标时显示的漂亮的身份验证弹出窗口。

有人可以回答吗,为什么我现在看不到身份验证弹出窗口?

就我而言,我正在使用 JWT 令牌身份验证.NET Core API。我使用以下代码使用授权令牌配置 swagger。此代码将添加全局安全要求。

在启动中 Class ConfigureServices 方法。

        //Swagger Configuration

        services.AddSwaggerGen(options =>
        {
            options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
            {
                Title = "API",
                Version = "v2",
                Description = "Your Api Description"
            });
            options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
            {
                Description = "JWT Authorization header using the Bearer scheme (Example: 'Bearer 12345abcdef')",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.ApiKey,
                Scheme = "Bearer"
            });
            options.AddSecurityRequirement(new OpenApiSecurityRequirement
            {
                {
                    new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference
                        {
                            Type = ReferenceType.SecurityScheme,
                            Id = "Bearer"
                        }
                    },
                    Array.Empty<string>()
                }
            });
        });

并在配置方法中

        app.UseSwagger();

        app.UseSwaggerUI(options =>
        {
            options.SwaggerEndpoint("/swagger/v1/swagger.json", "API");
        });

在 运行 之后,API 项目授权按钮将出现在右侧。单击授权按钮打开授权弹出窗口,然后使用“Bearer token”在文本框中传递令牌。

授权对我来说很好。

假设您有一些使用 [Authorize] 属性保护的端点(也可以放在控制器上)。

[Route("")]
public class HelloController : ControllerBase
{
    [Authorize]
    [HttpGet("secure")]
    public IActionResult GetSomethingPrivate()
    {
        return Ok("secret");
    }

    [HttpGet("public")]
    public IActionResult GetSomethingPublic()
    {
        return Ok("hey");
    }
}

您需要定义适合您需要的安全方案。 但不要全局要求它,而是将其添加到操作过滤器中。在这里我添加了一个简单的令牌 auth:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "ApiPlayground", Version = "v1" });
        c.AddSecurityDefinition("token", new OpenApiSecurityScheme
        {
            Type = SecuritySchemeType.ApiKey,
            In = ParameterLocation.Header,
            Name = HeaderNames.Authorization,
            Scheme = "Bearer"
        });
        // dont add global security requirement
        // c.AddSecurityRequirement(/*...*/);
        c.OperationFilter<SecureEndpointAuthRequirementFilter>();
    });
}

这是引用我们刚刚创建的 token 身份验证方案的操作过滤器。它检查端点是否需要身份验证,然后添加要求。

internal class SecureEndpointAuthRequirementFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (!context.ApiDescription
            .ActionDescriptor
            .EndpointMetadata
            .OfType<AuthorizeAttribute>()
            .Any())
        {
            return;
        }

        operation.Security = new List<OpenApiSecurityRequirement>
        {
            new OpenApiSecurityRequirement
            {
                [new OpenApiSecurityScheme
                {
                    Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "token" }
                }] = new List<string>()
            }
        };
    }
}

当您 运行 应用程序时,它会如您所愿地运行:

验证弹出窗口也是如此:

奖励:使用基本身份验证

使用以下值定义新的安全方案:

public void ConfigureServices(IServiceCollection services)
{
    // ...
    services.AddSwaggerGen(c =>
    {
        // ...
        // basic auth scheme (username + password)
        c.AddSecurityDefinition("basic", new OpenApiSecurityScheme
        {
            Type = SecuritySchemeType.Http,
            Scheme = "basic"
        });
        // dont add global security requirement
        // c.AddSecurityRequirement(/*...*/);
        c.OperationFilter<SecureEndpointAuthRequirementFilter>();
    });
}

然后更新操作过滤器以引用 basic 身份验证方案:

internal class SecureEndpointAuthRequirementFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (!context.ApiDescription
            .ActionDescriptor
            .EndpointMetadata
            .OfType<AuthorizeAttribute>()
            .Any())
        {
            return;
        }

        operation.Security = new List<OpenApiSecurityRequirement>
        {
            new OpenApiSecurityRequirement
            {
                [new OpenApiSecurityScheme
                {
                    Reference = new OpenApiReference
                    {
                        Type = ReferenceType.SecurityScheme, 
                        Id = "basic" // <-- changed "token" -> "basic"
                    }
                }] = new List<string>()
            }
        };
    }
}

验证弹出窗口如下所示:

登录后,请求包括正确的 Authorization header.