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

Since it went more than a month since I asked this one. Here is how I did it.

I deleted the following code from 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>() },
});

And I added the following one:

c.OperationFilter<AddAuthHeaderOperationFilter>();

And of course the 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[] { } }
                });
            }
        }
    }

Shortly, this OperationFilter class only adds the locker icon to methods that require Authorization. The locker is always Opened though. So not the perfect solution, but for now is ok.

Here is how it looks:

enter image description here

Note: So if you want to test the API, you first get a token and then fill it where needed.


For Swashbuckle 5.0.0 and later AddAuthHeaderOperationFilter from @G.Dimov's answer changes to following (with some additional style edits):

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[] { } }
            });
        }
    }
}

EDIT

Swagger UI refuses to send the Authorization header if it is defined as a parameter. So probably better option will be to create a security definition in the SwaggerGen service configuration (usually in 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"
            });
    }
}

And then add a security requirement with a reference to a definition to the operation:

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]
                }
            }
        );
    }
}