繁体   English   中英

ASP Net Core 2.2 仅向需要授权的方法添加储物柜图标 - Swagger UI

[英]ASP Net Core 2.2 add locker icon only to methods that require authorization - Swagger UI

版本:

  • ASP 网络核心 Web API - 2.2
  • Swashbuckle.AspNetCore - 4.0.1

我目前有什么?

我已经在我的 Web API 项目中实现了 swagger。 我在需要它的方法上使用带有[Authorize]属性的 JWT 授权。

所以我想要一种能够发送需要授权的请求的简单方法。 在我的ConfigureServices类中,我添加了以下逻辑。

services.AddSwaggerGen(c =>
{

    // Other swagger options

    c.AddSecurityDefinition("Bearer", new ApiKeyScheme
    {
        In = "header",
        Description = "Please enter into field the word 'Bearer' following by space and your JWT token",
        Name = "Authorization",
        Type = "apiKey"
    });
    c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>
    {
        { "Bearer", Enumerable.Empty<string>() },
    });

    // Other swagger options
});

它的作用如下:
它在 swagger 中添加了一个新按钮 - 授权。

在此处输入图片说明

问题是,它还在每个方法旁边添加了一个“打开”储物柜图标。 尽管如此,其中一些需要授权。

在此处输入图片说明

当我使用授权按钮成功授权时(它基本上为每个请求添加了标头授权),我在所有请求上都会收到一个“关闭”的储物柜。 在此处输入图片说明

我知道这可能是指示将通过请求发送授权令牌的所需功能。 我想要一种方法来显示哪些方法需要授权,哪些不需要。

我想要什么?

例如,匿名方法的“打开”储物柜和具有[Authorize]属性的方法的“关闭”储物柜。

它可能是一个附加图标,在此旁边或修改此图标的行为,没问题。 我怎样才能做到这一点?

可能的解决方案?

我相信一个可能的解决方案是制作一个 OperationFilter 并检查所有方法,并将“某物”仅附加到那些具有[Authorize]属性的方法上。 这是最好的解决方案吗? 如果是这样,您将如何实施?

因为我问这个已经一个多月了。 这是我如何做到的。

我从Startup.cs删除了以下代码:

c.AddSecurityDefinition("Bearer", new ApiKeyScheme
{
    In = "header",
    Description = "Please enter into field the word 'Bearer' following by space and your JWT token",
    Name = "Authorization",
    Type = "apiKey"
});
c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>
{
    { "Bearer", Enumerable.Empty<string>() },
});

我添加了以下内容:

c.OperationFilter<AddAuthHeaderOperationFilter>();

当然还有AddAuthHeaderOperationFilter.cs

    public class AddAuthHeaderOperationFilter : IOperationFilter
    {
        private readonly IHttpContextAccessor httpContextAccessor;

        public AddAuthHeaderOperationFilter(IHttpContextAccessor httpContextAccessor)
        {
            this.httpContextAccessor = httpContextAccessor;
        }

        public void Apply(Operation operation, OperationFilterContext context)
        {
            var filterDescriptor = context.ApiDescription.ActionDescriptor.FilterDescriptors;
            var isAuthorized = filterDescriptor.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter);
            var allowAnonymous = filterDescriptor.Select(filterInfo => filterInfo.Filter).Any(filter => filter is IAllowAnonymousFilter);

            if (isAuthorized && !allowAnonymous)
            {
                if (operation.Parameters == null)
                    operation.Parameters = new List<IParameter>();

                operation.Parameters.Add(new NonBodyParameter
                {
                    Name = "Authorization",
                    In = "header",
                    Description = "JWT access token",
                    Required = true,
                    Type = "string",
                    //Default = $"Bearer {token}"
                });

                operation.Responses.Add("401", new Response { Description = "Unauthorized" });
                operation.Responses.Add("403", new Response { Description = "Forbidden" });

                operation.Security = new List<IDictionary<string, IEnumerable<string>>>();

                //Add JWT bearer type
                operation.Security.Add(new Dictionary<string, IEnumerable<string>>
                {
                    { "Bearer", new string[] { } }
                });
            }
        }
    }

很快,这个 OperationFilter 类只将储物柜图标添加到需要授权的方法中。 储物柜总是打开的。 所以不是完美的解决方案,但现在还可以。

这是它的外观:

在此处输入图片说明

注意:所以如果你想测试 API,你首先得到一个令牌,然后在需要的地方填写它。

对于来自@G.Dimov 的 Swashbuckle 5.0.0 和更高版本的 AddAuthHeaderOperationFilter,答案更改为以下(带有一些额外的样式编辑):

public class AddAuthHeaderOperationFilter : IOperationFilter
{
    private readonly IHttpContextAccessor httpContextAccessor;

    public AddAuthHeaderOperationFilter(IHttpContextAccessor httpContextAccessor)
    {
        this.httpContextAccessor = httpContextAccessor;
    }

    public void Apply(Operation operation, OperationFilterContext context)
    {
        var filterDescriptor = context.ApiDescription.ActionDescriptor.FilterDescriptors;
        var isAuthorized = filterDescriptor.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter);
        var allowAnonymous = filterDescriptor.Select(filterInfo => filterInfo.Filter).Any(filter => filter is IAllowAnonymousFilter);

        if (isAuthorized && !allowAnonymous)
        {
            if (operation.Parameters == null)
                operation.Parameters = new List<IParameter>();

            operation.Parameters.Add(new NonBodyParameter
            {
                Name = "Authorization",
                In = "header",
                Description = "JWT access token",
                Required = true,
                Type = "string"
            });

            operation.Responses.Add("401", new Response { Description = "Unauthorized" });
            operation.Responses.Add("403", new Response { Description = "Forbidden" });

            operation.Security = new List<IDictionary<string, IEnumerable<string>>>();

            //Add JWT bearer type
            operation.Security.Add(new Dictionary<string, IEnumerable<string>>
            {
                { "Bearer", new string[] { } }
            });
        }
    }
}

编辑

如果将授权标头定义为参数,Swagger UI 将拒绝发送它。 所以可能更好的选择是在 SwaggerGen 服务配置中创建一个安全定义(通常在 Startup.ConfigureServices 中):

public void ConfigureServices(IServiceCollection services)
{
    // Service configuration
    services.AddSwaggerGen(c =>
    {
        // Configure Swagger
        // "Bearer" is the name for this definition. Any other name could be used
        c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
            {
                Description = "Use bearer token to authorize",
                Type = SecuritySchemeType.Http,
                Scheme = "bearer",
                BearerFormat = "JWT"
            });
    }
}

然后添加一个安全要求,并引用对操作的定义:

public class AddAuthorizationHeaderOperationHeader : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        var actionMetadata = context.ApiDescription.ActionDescriptor.EndpointMetadata;
        var isAuthorized = actionMetadata.Any(metadataItem => metadataItem is AuthorizeAttribute);
        var allowAnonymous = actionMetadata.Any(metadataItem => metadataItem is AllowAnonymousAttribute);

        if (!isAuthorized || allowAnonymous)
        {
            return;
        }
        if (operation.Parameters == null)
            operation.Parameters = new List<OpenApiParameter>();

        operation.Security = new List<OpenApiSecurityRequirement>();

        //Add JWT bearer type
        operation.Security.Add(new OpenApiSecurityRequirement
            {
                {
                    new OpenApiSecurityScheme
                    {                            
                        Reference = new OpenApiReference
                        {                               
                            Type = ReferenceType.SecurityScheme,
                            // Definition name. 
                            // Should exactly match the one given in the service configuration
                            Id = "Bearer"
                        }
                    }, new string[0]
                }
            }
        );
    }
}

请按照以下步骤使用正确的挂锁实施 Swagger-

第1步

添加一个类并使用IOperationFilter接口继承这个类。 之后,实现IOperationFilter接口的Apply方法定义。

要实现Apply方法,您需要OpenApiOperationOpenApiOperation类型的两个参数。

public class AddSwaggerService : IOperationFilter
    {     

        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            var actionMetadata = context.ApiDescription.ActionDescriptor.EndpointMetadata;
            var isAuthorized = actionMetadata.Any(metadataItem => metadataItem is AuthorizeAttribute);
            var allowAnonymous = actionMetadata.Any(metadataItem => metadataItem is AllowAnonymousAttribute);

            if (!isAuthorized || allowAnonymous)
            {
                return;
            }
            if (operation.Parameters == null)
                operation.Parameters = new List<OpenApiParameter>();

            operation.Security = new List<OpenApiSecurityRequirement>();

            
            var security = new OpenApiSecurityRequirement
            {
                {
                    new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference
                        {
                            Type = ReferenceType.SecurityScheme,                            
                            Id = "Bearer"
                        }
                    }, new List<string>()
                }
            };
            //add security in here
            operation.Security.Add(security);
        }

第2步

Startup.cs ConfigureServices方法中添加swagger Generation Service 在此服务中,您需要添加我们在步骤 1 中实现的以下行。

c.OperationFilter<AddSwaggerService>();

 public void ConfigureServices(IServiceCollection services)
        {

//.........other Services.........
//.........other Services.........
//.........other Services.........

services.AddSwaggerGen(c =>
                c.SwaggerDoc(AppConstantKeys.APIName, new OpenApiInfo { Title = "title", Version = "APIVersion" });

                c.OperationFilter<AddSwaggerService>();
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description ="SwaggerShortDescription",
                    Name = "HeaderName",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey,

                });
            });

//.........other Services.........
//.........other Services.........
//.........other Services.........

}

步骤 3在中间件管道中添加 swagger。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
//.........other middlewares.........
//.........other middlewares.........
//.........other middlewares.........
//.........other middlewares.........


            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "SwaggerUIName");
                c.DocumentTitle = "SwaggerUITitle";
                c.DocExpansion(DocExpansion.None);
                c.RoutePrefix = string.Empty;
            });

//.........other middlewares.........
//.........other middlewares.........
//.........other middlewares.........
//.........other middlewares.........


}


第四步

构建和运行。

在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM