Swagger UI -仅对某些端点进行身份验证

h5qlskok  于 2023-11-18  发布在  其他
关注(0)|答案(2)|浏览(188)

我在一个.NET核心API项目中使用Swagger。有没有一种方法可以在Swagger UI中仅对某些端点应用JWT身份验证?
我只在一些调用上设置了[Authorize]属性(也尝试在不需要身份验证的调用上设置[AllowAnonymous]),但是当我打开Swagger UI页面时,所有端点上都有锁符号。

zengzsys

zengzsys1#

您必须创建一个IOperationFilter,以便仅将OpenApiSecurityScheme添加到某些端点。如何做到这一点,请参见in this blog post(针对.NET Core 3.1进行了调整,来自同一篇博客文章中的评论)。
在我的例子中,如果没有显式添加[AllowAnonymous],则所有端点默认为[Authorize](也在链接的博客文章中描述)。然后我创建了以下IOperationFilter的实现:

public class SecurityRequirementsOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (!context.MethodInfo.GetCustomAttributes(true).Any(x => x is AllowAnonymousAttribute) &&
            !(context.MethodInfo.DeclaringType?.GetCustomAttributes(true).Any(x => x is AllowAnonymousAttribute) ?? false))
        {
            operation.Security = new List<OpenApiSecurityRequirement>
            {
                new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme {
                            Reference = new OpenApiReference {
                                Type = ReferenceType.SecurityScheme,
                                Id = "bearer"
                            }
                        }, new string[] { }
                    }
                }
            };
        }
    }
}

字符串
如果不将所有端点默认为[Authorize],则必须调整if语句。
最后,在调用services.AddSwaggerGen(options => { ... }(通常在Startup.cs中)的地方,我有以下一行:

options.OperationFilter<SecurityRequirementsOperationFilter>();


请注意,上面的代码行将在同一位置替换(假定)现有的options.AddSecurityRequirement(...)调用。

vc9ivgsu

vc9ivgsu2#

下面是最好的解决方案,如果你使用[Authorize]属性:

public static class SwaggerAuthExtension
    {
        private static readonly string authType = "Bearer JWT";

        private static readonly OpenApiSecurityRequirement requirement = new()
        {{
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Type = ReferenceType.SecurityScheme,
                    Id = authType
                }
            },
            new string[]{}
        }};

        private static readonly OpenApiSecurityScheme scheme = new()
        {
            In = ParameterLocation.Header,
            Description = "Please enter a valid token",
            Name = "Authorization",
            Type = SecuritySchemeType.Http,
            BearerFormat = "JWT",
            Scheme = "Bearer"
        };

        public static void AddJWTAuth(this SwaggerGenOptions option)
        {
            option.AddSecurityDefinition(authType, scheme);
            option.OperationFilter<SecurityRequirementsOperationFilter>();
        }

        public static void AddSwaggerGenWithJWTAuth(this IServiceCollection services)
        {
            services.AddSwaggerGen(opt => opt.AddJWTAuth());
        }

        private class SecurityRequirementsOperationFilter : IOperationFilter
        {
            public void Apply(OpenApiOperation operation, OperationFilterContext context)
            {
                if (
                    context.MethodInfo.GetCustomAttributes(true).Any(x => x is AuthorizeAttribute) ||
                    (context.MethodInfo.DeclaringType?.GetCustomAttributes(true).Any(x => x is AuthorizeAttribute) ?? false)
                )
                {
                    operation.Security = new List<OpenApiSecurityRequirement>
                    {
                        requirement
                    };
                }
            }
        }
    }

字符串
使用方法:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSwaggerGenWithJWTAuth();


var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSwaggerGen(opt => opt.AddJWTAuth());


基于Julian的回答,我修改了SecurityRequirementsOperationFilter类中的if语句,用于搜索AuthorizeAttribute

相关问题