Another customized implementation for:
- Web API (.Net 5)
- Swashbuckle.AspNetCore.Swagger (6.2.3)
- Swashbuckle.AspNetCore.SwaggerGen (6.2.3)
- Swashbuckle.AspNetCore.SwaggerUI (6.2.3)
Following some of the answers from this thread did get me a required field for Authorization. However I had run into a different problems. I need to have the followings fixed:
- Display a lock sign beside API actions where authentication is required. For anonymous actions there is no point having a required
Authorization
field.
- For every API endpoi I did not want to input the Authorization key. It becomes a redundant work if we are to test couple of APIs at one go. So I needed a single point where I would put the Auth key and execute the APIs from the Swagger UI. The Swagger UI would handle the Auth part where required.
- I did not want to add custom filter or codes in the controller actions where I might have to edit many actions.
- Last but not the least, I had a problem where I did get the required Authorization field on the Swagger UI but that was not being post back in request header along the other API fields.
To overcome the above issues I have done the followings:
- Create a
IOperationFilter
type filter to indicate which API endpoints requires authentication and which ones are anonymous type
- A button on the Swagger UI to bring a popup to input my Auth token that would be used automatically with the API calls from the Swagger UI
Here are the codes:
#Step-1: The custom IOperationFilter
type filrer:
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (context.ApiDescription.ActionDescriptor is ControllerActionDescriptor descriptor)
{
// If [AllowAnonymous] is not applied or [Authorize] or Custom Authorization filter is applied on either the endpoint or the controller
if (!context.ApiDescription.CustomAttributes().Any((a) => a is AllowAnonymousAttribute)
&& (context.ApiDescription.CustomAttributes().Any((a) => a is AuthorizeAttribute)
|| descriptor.ControllerTypeInfo.GetCustomAttribute<AuthorizeAttribute>() != null))
{
if (operation.Security == null)
operation.Security = new List<OpenApiSecurityRequirement>();
operation.Security.Add(
new OpenApiSecurityRequirement{
{
new OpenApiSecurityScheme
{
Name = "Authorization",
In = ParameterLocation.Header,
BearerFormat = "Bearer token",
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[]{ }
}
});
}
}
}
Then in the startup.cs file, within the ConfigureServices
method add the filter like this:
services.AddSwaggerGen(options =>
{
...
options.OperationFilter<AddRequiredHeaderParameter>();
...
...
}
Doing the above will add an icon to the API endpoints where Authentication is required. Here is the result:
#Step-2: Then we need the Auth token input UI. Add the following code right after the line in the startup.cs where you have added the IOperationFilter
filter:
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
{
Name = "Authorization",
Type = SecuritySchemeType.Http,
Scheme = "Bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description = "JWT Authorization header. \r\n\r\n Enter the token in the text input below.,
});
This will get you a Authorize button at the top of the API descriptor page. Clicking the button will bring a popup window where you can input the Auth token and have it passed down with each API call.