前言
上次,我们实现了《ASP.NET Core 同时支持多种认证方式》:
services.AddAuthentication().AddDemoAuthentication(options => { }).AddJwtBearer(options =>{...});
我们还希望为 Swagger 也添加多种认证支持。
原来为支持 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 同时支持多种认证方式。
添加微信号【MyIO666】,邀你加入技术交流群