17

I'm creating an API with .Net Core 2.1 and using JSON Web Token (JWT) for authentication.

I have 2 controllers: AuthenticationController and UserController. I have decorated AuthenticationController with [AllowAnonymous] and UserController with [Authorize].

Swagger is working correctly: it allows me to hit the endpoints in AuthenticationController (SignUp/SignIn) without requesting authorization, and it does request JWT to hit the endpoints in UserController.

However, in Swagger UI, every endpoint of every controller shows a padlock icon as if all of them required authorization. Everything works correctly and as expected but it just bothers me that the endpoints that don't require authorization still show that padlock icon.

Is there a way to remove the padlock icon from those endpoints?

I believe that something can be done with the OperationFilter but I couldn't find a way.

Divyang Desai
  • 7,483
  • 13
  • 50
  • 76
g0np
  • 191
  • 1
  • 10

4 Answers4

20

Absolutly, you need to use an IOperationFilter to remove the padlock icon for the anonymous endpoints.

// AuthResponsesOperationFilter.cs
public class AuthResponsesOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        var authAttributes = context.MethodInfo.DeclaringType.GetCustomAttributes(true)
            .Union(context.MethodInfo.GetCustomAttributes(true))
            .OfType<AuthorizeAttribute>();

        if (authAttributes.Any())
        {
            var securityRequirement = new OpenApiSecurityRequirement()
            {
                {
                    // Put here you own security scheme, this one is an example
                    new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference
                        {
                            Type = ReferenceType.SecurityScheme,
                            Id = "Bearer"
                        },
                        Scheme = "oauth2",
                        Name = "Bearer",
                        In = ParameterLocation.Header,
                    },
                    new List<string>()
                }
            };
            operation.Security = new List<OpenApiSecurityRequirement> { securityRequirement };
            operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" });
        }
    }
}

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

Do not forget to remove any call to AddSecurityRequirement in your Startup.cs, otherwise the padlock icon would still be added to all endpoints.

Bruno Martins
  • 882
  • 2
  • 10
  • 21
3

this solution works for SwashBuckle 5.0.0-rc5 and .Net Core 3.1.1 Web API. You need to :

  1. implement an IOperationFilter interface,
  2. add c.OperationFilter(); in your Startup.cs file
  3. finally remove any call of AddSecurityRequirement

public class AuthResponsesOperationFilter: 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)) {
      operation.Security = new List < OpenApiSecurityRequirement > {
        new OpenApiSecurityRequirement {
          {
            new OpenApiSecurityScheme {
              Reference = new OpenApiReference {
                Type = ReferenceType.SecurityScheme,
                  Id = "bearer"
              }
            }, new string[] {}
          }
        }
      };
    }

  }
}
  • "finally remove any call of AddSecurityRequirement" -> This info was exactly what I needed, as I added Security Requirement for all endpoints in another place in my code. Thanks! – ruzgarustu Apr 26 '23 at 08:15
3

Install Package

Swashbuckle.AspNetCore.Filters

And then when you document your swagger you need to add the below line

  options.OperationFilter<SecurityRequirementsOperationFilter >();

Here's an example from .NET 6

builder.Services.AddSwaggerGen(options => {
    options.SwaggerDoc("v1", new OpenApiInfo
    {
        Title = "API",
        Version = "v1",
        Description = "API using .NET 6"
    });
    options.OperationFilter<SecurityRequirementsOperationFilter>();
});

Swagger UI

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
Aya Osama
  • 51
  • 2
1

In startup.cs -> services.AddSwaggerGen , you need to add c.OperationFilter<ApplyOAuth2Security>(); and add below method in stratup.cs which will enable lock/authorize icon in Swagger UI for the action methods which are marked as Authorize only.

private class ApplyOAuth2Security : IOperationFilter
        {
            /// <inheritdoc/>
            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 authorizationRequired = context.MethodInfo.CustomAttributes.Any(a => a.AttributeType.Name == "AuthorizeAttribute");

                if (isAuthorized && authorizationRequired)
                {
                    operation.Security = new List<IDictionary<string, IEnumerable<string>>>
                    {
                        new Dictionary<string, IEnumerable<string>>
                        {
                             { "oauth2", new string[] { "openid" } },
                        },
                    };
                }
            }
        }
Ruben Helsloot
  • 12,582
  • 6
  • 26
  • 49
Anupam Maiti
  • 225
  • 1
  • 2
  • 10