Search code examples
c#asp.net-coreswagger-uiswashbuckle.aspnetcore

C#: Swagger/Swashbuckle - Connect security schemes with "AND"


I have an ASP.NET Core Api where it is required to use multiple authentication schemes for one operation. I am trying to document those operations with displaying all required authentication schemes in Swagger UI. Therefore I use the Swashbuckle.AspNetCore (5.1.0) library for a dynamic adding of OpenApiSecurityRequirement to the OpenApiOperation in an IOperationFilter:

if (authorizeAttributes.Any(x => x.AuthenticationSchemes.Contains(InternalControllerBasicAuthentication.AuthenticationScheme)))
{
       requirements.Add(new OpenApiSecurityRequirement
       {
             {
                   new OpenApiSecurityScheme {
                        Reference = new OpenApiReference {
                            Type = ReferenceType.SecurityScheme,
                            Id = "credentials"
                        }
                   },
                   new [] { "Basic <credentials-value>" }
             }
      });
} 

if (authorizeAttributes.Any(x => x.AuthenticationSchemes.Contains(OneTimePasswordAuthentication.AuthenticationScheme)))
{
      requirements.Add(new OpenApiSecurityRequirement
      {
             {
                   new OpenApiSecurityScheme {
                        Reference = new OpenApiReference {
                            Type = ReferenceType.SecurityScheme,
                            Id = "one-time-password"
                        }
                   },
                   new [] { "Basic <one-time-password-value>" }
             }
      });
}

operation.Security = new List<OpenApiSecurityRequirement>(requirements);

Furthemore I use the SwaggerGenOptions to register all possible schemes:

var oneTimePasswordScheme = new OpenApiSecurityScheme
{
    Name = "one-time-password",
    In = ParameterLocation.Header,
    Scheme = "one-time-password",
    Type = SecuritySchemeType.ApiKey
};

options.AddSecurityDefinition("one-time-password", oneTimePasswordScheme);

var credentialsScheme = new OpenApiSecurityScheme
{
    Name = "credentials",
    In = ParameterLocation.Header,
    Scheme = "credentials",
    Type = SecuritySchemeType.ApiKey
};

options.AddSecurityDefinition("credentials", credentialsScheme);

Everything works fine except for Swagger using the OR connector in the UI:

enter image description here

Is there a way to configure Swagger using the AND connector?

Any help will be highly appreciated!


Solution

  • Instead of adding a OpenApiSecurityRequirement for each OpenApiSecurityScheme, it is necessary to put all OpenApiSecurityScheme objects into a single OpenApiSecurityRequirement.

    Connects security requirements with OR:

    var requirements = new List<OpenApiSecurityRequirement>();
    requirements.Add(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme {
                Reference = new OpenApiReference {
                    Type = ReferenceType.SecurityScheme,
                    Id = "scheme-1"
                }
            },
            new [] { "scheme-1-value" }
        }
    });
    
    requirements.Add(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme {
                Reference = new OpenApiReference {
                    Type = ReferenceType.SecurityScheme,
                    Id = "scheme-2"
                }
            },
            new [] { "scheme-2-value" }
        }
    });
    
    operation.Security = new List<OpenApiSecurityRequirement>(requirements);
    

    Connects security requirements with AND:

    var requirement = new OpenApiSecurityRequirement();
    requirement.Add(new OpenApiSecurityScheme {
            Reference = new OpenApiReference {
                Type = ReferenceType.SecurityScheme,
                Id = "scheme-1"
            }
        },
        new [] { "scheme-1-value" }
    );
    
    requirement.Add(new OpenApiSecurityScheme {
            Reference = new OpenApiReference {
                Type = ReferenceType.SecurityScheme,
                Id = "scheme-2"
            }
        },
        new [] { "scheme-2-value" }
    );
    
    operation.Security = new List<OpenApiSecurityRequirement> { requirement };