Swashbuckle.WebApi icon indicating copy to clipboard operation
Swashbuckle.WebApi copied to clipboard

Provide a way to generate an empty JSON security array for an operation

Open jez9999 opened this issue 4 years ago • 0 comments

In order to mark operations as requiring authorization in a Swagger document, you can individually mark them one-by-one as requiring security:

services.AddSwaggerGen(options => {
    options.OperationFilter<SwaggerRequireAuth>(apiScope);
});
//...
internal class SwaggerRequireAuth : IOperationFilter {
    private readonly string _apiScope;

    public SwaggerNoAnonymousAuth(string apiScope) {
        _apiScope = apiScope;
    }

    public void Apply(OpenApiOperation operation, OperationFilterContext context) {
        bool isAnonymous = context.MethodInfo.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>().Count() > 0;

        if (!isAnonymous) {
            operation.Security = new List<OpenApiSecurityRequirement> {
                new OpenApiSecurityRequirement {
                    {
                        // Scheme required to access all non-anonymous API operations
                        new OpenApiSecurityScheme {
                            Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
                        },
                        // Scopes required to access all non-anonymous API operations
                        new[] { _apiScope }
                    }
                }
            };
        }
    }
}

However, this will rather bloat the Swagger JSON file by separately specifying the same security for every single operation:

"security": [
  {
    "oauth2": [
      "my-api-scope"
    ]
  }
]

If your API has only a few operations that are anonymous, and don't require authentication, with every other operation requiring the same authentication, the more efficient way to indicate this is to apply a global security requirement and then specify an empty JSON security array for the few operations that are anonymous:

services.AddSwaggerGen(options => {
    options.AddSecurityRequirement(new OpenApiSecurityRequirement {
        {
            // Scheme required to access all non-anonymous API operations
            new OpenApiSecurityScheme {
                Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
            },
            // Scopes required to access all non-anonymous API operations
            new[] { apiScope }
        }
    });
});
//...
internal class SwaggerNoAnonymousAuth : IOperationFilter {
    private readonly string _apiScope;

    public SwaggerNoAnonymousAuth(string apiScope) {
        _apiScope = apiScope;
    }

    public void Apply(OpenApiOperation operation, OperationFilterContext context) {
        bool isAnonymous = context.MethodInfo.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>().Count() > 0;

        if (isAnonymous) {
            operation.Security = new List<OpenApiSecurityRequirement>();
        }
    }
}

... to generate:

"security": []

At least, that's what I wish it would generate, which should mark the few anonymous methods I have as anonymous in the Swagger document. Unfortunately, setting .Security to an empty list removes the security element altogether, meaning the operation gets the global security applied to it.

Can a way be added to get the Swagger document to have an empty JSON security array for certain operations?

jez9999 avatar May 07 '20 10:05 jez9999