I am using Swashbuckle.AspNetCore 5.0.0-rc2 in one of my .Net Core 2.2 REST projects. Within my project I am serving two different apis which are logically connected to each other.
Today, I managed to seperate my swagger documentations to have one swagger endpoint per api containing only the corresponding api controllers.
I managed to do this by adding a specified group name to the api explorer settings of the controllers:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiExplorerSettings(GroupName = "contracts")]
public class ContractsController : BaseController
[Authorize(AuthenticationSchemes = "BasicAuthentication")]
[ApiExplorerSettings(GroupName = "clearing")]
public class ClearingController : BaseController
With that settings I was able to specify to different endpoints for swagger within my Startup.cs
// Enable documentation middleware
app.UseSwagger(so =>
{
so.RouteTemplate = "api/doc/{documentName}/swagger.json";
});
app.UseSwaggerUI(suo =>
{
suo.SwaggerEndpoint("/api/doc/contracts/swagger.json", "Contracts API");
suo.SwaggerEndpoint("/api/doc/clearing/swagger.json", "Clearing API");
suo.RoutePrefix = "api/doc";
suo.SupportedSubmitMethods(SubmitMethod.Get, SubmitMethod.Post, SubmitMethod.Patch, SubmitMethod.Delete);
});
That worked and everything was fine.
Now as you probably noticed, I am using different authorization methods for the controllers of each api. The first, the contracts api, is using a JWT Token authorization, while the second one, the clearing api is using a Basic authorization.
I thought, the swagger ui would automatically use the correct Authorization method by the "Authorize" Attribute, but I was wrong.
Well I added both authorization methods to the swagger ui middleware like this:
options.AddSecurityDefinition("Bearer", GetSwaggerTokenSecurityScheme());
options.AddSecurityDefinition("Basic", GetSwaggerBasicSecurityScheme());
options.AddSecurityRequirement(GetSwaggerJwtSecurityRequirement());
options.AddSecurityRequirement(GetSwaggerBasicSecurityRequirement());
Heres my full swagger configuration code:
/// <summary>
/// Configures the swagger generation
/// </summary>
/// <param name="config">The swagger configuration</param>
/// <param name="options">The swagger gen options instance</param>
public static void ConfigureSwaggerGen(IConfiguration config, SwaggerGenOptions options)
{
var swaggerConfig = config.Get<SwaggerConfiguration>();
AddSwaggerDocPerApiType(swaggerConfig, options);
options.AddSecurityDefinition("Bearer", GetSwaggerTokenSecurityScheme());
options.AddSecurityDefinition("Basic", GetSwaggerBasicSecurityScheme());
options.AddSecurityRequirement(GetSwaggerJwtSecurityRequirement());
options.AddSecurityRequirement(GetSwaggerBasicSecurityRequirement());
if (!swaggerConfig.SwaggerIncludeXml)
{
return;
}
var xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml");
xmlFiles.ToList().ForEach(f => options.IncludeXmlComments(f));
options.DescribeAllEnumsAsStrings();
}
/// <summary>
/// Adds a swagger documentation for each api type
/// </summary>
/// <param name="config">The swagger configuration</param>
/// <param name="options">The swagger gen options instance</param>
private static void AddSwaggerDocPerApiType(SwaggerConfiguration config, SwaggerGenOptions options)
{
options.SwaggerDoc("contracts", GetSwaggerInformationParams(config, "Contracts"));
options.SwaggerDoc("clearing", GetSwaggerInformationParams(config, "Clearing"));
}
/// <summary>
/// Generates swagger information params object
/// according to the given configuration
/// </summary>
/// <param name="config">The configuration</param>
/// <param name="apiType">The api type</param>
/// <returns>The swagger information</returns>
private static OpenApiInfo GetSwaggerInformationParams(SwaggerConfiguration config, string apiType = "")
{
var title = string.IsNullOrEmpty(apiType) ? config.SwaggerTitle : apiType;
var version = string.IsNullOrEmpty(apiType) ? Assembly.GetExecutingAssembly().GetName().Version.ToString() : apiType;
var swaggerInfo = new OpenApiInfo()
{
Title = title,
Version = version.ToLower(),
Description = config.SwaggerDescription,
Contact = new OpenApiContact()
{
Name = config.SwaggerCompany,
Email = config.SwaggerContactMail,
Url = new Uri(config.SwaggerContactUrl)
}
};
return swaggerInfo;
}
/// <summary>
/// Generates the swagger jwt security scheme object
/// </summary>
/// <returns>The swagger jwt security scheme</returns>
private static OpenApiSecurityScheme GetSwaggerTokenSecurityScheme()
{
var scheme = new OpenApiSecurityScheme
{
Description = "JWT authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "JwtAuthorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
};
return scheme;
}
/// <summary>
/// Generates the swagger basic security scheme object
/// </summary>
/// <returns>The swagger basic security scheme</returns>
private static OpenApiSecurityScheme GetSwaggerBasicSecurityScheme()
{
var scheme = new OpenApiSecurityScheme
{
Description = "Basic authorization header. Example: \"Authorization: username:password\"",
Name = "BasicAuthorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "basic"
};
return scheme;
}
/// <summary>
/// Generates the swagger security scheme object
/// </summary>
/// <returns>The swagger security scheme</returns>
private static OpenApiSecurityRequirement GetSwaggerJwtSecurityRequirement()
{
var req = new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme()
{
Reference = new OpenApiReference() {Type = ReferenceType.SecurityScheme, Id = "Bearer"}
},
new[] {"readAccess", "writeAccess"}
}
};
return req;
}
/// <summary>
/// Generates the swagger security scheme object
/// </summary>
/// <returns>The swagger security scheme</returns>
private static OpenApiSecurityRequirement GetSwaggerBasicSecurityRequirement()
{
var req = new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme()
{
Reference = new OpenApiReference() {Type = ReferenceType.SecurityScheme, Id = "Basic"}
},
new[] {"readAccess", "writeAccess"}
}
};
return req;
}
Now what I want to achieve is, that only the JWT token authorization is available for the contracts api controllers and only the basic authorization is available for the clearing api controllers.
At the moment I always have both authorization methods available for any api:
Does anybody know how to specify the security for the specific documentation endpoint only?
Best regards