原来为支持 JWT 认证,Swagger 相关配置代码是这样的:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApplication9", Version = "v1" });
c.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme()
{
Type = SecuritySchemeType.Http,
Scheme = "bearer",
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement {
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "bearerAuth"
}
},
new string[] { }
}
});
}
依葫芦画瓢,添加如下代码:
c.AddSecurityDefinition("demoAuth", new OpenApiSecurityScheme()
{
Type = SecuritySchemeType.ApiKey,
In = ParameterLocation.Query,
Name = "_key",
Scheme = "demo",
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement {
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "demoAuth"
}
},
new string[] { }
}
});
Swagger 可以正常显示 Authorize 页面:

但是,发现一个问题, 每次请求都会发送所有的认证信息,即使我们的方法只需要其中的一种:
解决思路
这是因为,我们使用了AddSecurityRequirement增加了全局的安全要求。应该根据方法上设置的AuthenticationSchemes添加对应的安全要求。针对这一需求,可以使用
IOperationFilter 接口实现操作筛选器。检索 ApiDescription 以获取相关信息,例如方法级别的AuthorizeAttribute。
实现
首先,创建SecuritySchemeOperationFilter继承自IOperationFilter,实现 Apply 方法:
internal class SecuritySchemeOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (context != null && operation != null)
{
var authenticationSchemes = context.MethodInfo
.GetCustomAttributes(true)
.OfType<AuthorizeAttribute>()
.SelectMany(attr => attr.AuthenticationSchemes.Split(','))
.Distinct();
string id = "";
if (authenticationSchemes.Contains("Bearer"))
{
id = "bearerAuth";
}
else if (authenticationSchemes.Contains("Demo"))
{
id = "demoAuth";
}
operation.Security = new List<OpenApiSecurityRequirement>
{
new OpenApiSecurityRequirement {
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = id
}
},
new string[] { }
}
}
};
}
}
}
在上面的代码中,我们检查 API 上指定的授权过滤器,并在授权过滤器的基础上添加了适当的安全要求。
另外,修改一下 Swagger 注册代码:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc(...);
c.AddSecurityDefinition("bearerAuth", ...);
c.AddSecurityDefinition("demoAuth", ...);
c.OperationFilter<SecuritySchemeOperationFilter>();
});
现在可以看到,对于OnlyForBearer API,只发送Bearer授权头,而不再发送Query查询字符串啦。
结论
今天,我们通过 IOperationFilter 实现了 Swagger 同时支持多种认证方式。