在ASP.NET Core 6中通过API密钥授权隐藏Swagger控制器与操作
在ASP.NET Core中实现Swagger动态权限过滤的方案
完全可以实现旧项目的功能,不需要放弃该特性,核心思路是让Swagger文档每次请求都动态生成,而非启动时预生成,结合请求中的API密钥过滤接口。以下是具体实现步骤:
1. 基础配置:启用HttpContext访问
首先注册IHttpContextAccessor,让过滤器能获取当前请求上下文:
builder.Services.AddHttpContextAccessor();
2. 配置Swagger禁用预生成缓存
修改Swagger注册逻辑,禁用预生成文档,确保每次请求Swagger JSON时都重新生成:
builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "你的API名称", Version = "v1" }); // 禁用启动时预生成文档,改为按需生成 c.GenerateDocsOnBuild = false; // 向过滤器注入HttpContextAccessor,用于获取当前请求的API密钥 var httpContextAccessor = builder.Services.BuildServiceProvider().GetRequiredService<IHttpContextAccessor>(); c.DocumentFilter<AuthDocumentFilter>(httpContextAccessor); c.OperationFilter<AuthOperationFilter>(httpContextAccessor); });
3. 实现动态过滤的DocumentFilter
自定义IDocumentFilter,根据请求中的API密钥验证权限,移除无权限的接口路径:
public class AuthDocumentFilter : IDocumentFilter { private readonly IHttpContextAccessor _httpContextAccessor; public AuthDocumentFilter(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { var httpContext = _httpContextAccessor.HttpContext; if (httpContext == null) return; // 从请求Header/查询参数中获取API密钥(根据你的实际传递方式调整) var apiKey = httpContext.Request.Headers["X-API-Key"].FirstOrDefault() ?? httpContext.Request.Query["apiKey"].FirstOrDefault(); // 验证API密钥,替换为你的实际权限校验逻辑 var hasAuthorizedAccess = ValidateApiKey(apiKey); // 无权限时,移除所有带[Authorize]特性的接口 if (!hasAuthorizedAccess) { var restrictedPaths = swaggerDoc.Paths .Where(p => context.ApiDescriptions .FirstOrDefault(a => a.RelativePath == p.Key)? .ActionDescriptor.EndpointMetadata.Any(m => m is AuthorizeAttribute) == true) .Select(p => p.Key) .ToList(); foreach (var path in restrictedPaths) { swaggerDoc.Paths.Remove(path); } } } private bool ValidateApiKey(string apiKey) { // 示例逻辑,替换为你的密钥校验规则 return !string.IsNullOrEmpty(apiKey) && apiKey == "你的有效API密钥"; } }
4. 可选:实现OperationFilter细化操作过滤
如果需要更精细的操作级过滤,可自定义IOperationFilter隐藏无权限的单个接口操作:
public class AuthOperationFilter : IOperationFilter { private readonly IHttpContextAccessor _httpContextAccessor; public AuthOperationFilter(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public void Apply(OpenApiOperation operation, OperationFilterContext context) { var httpContext = _httpContextAccessor.HttpContext; if (httpContext == null) return; var apiKey = httpContext.Request.Headers["X-API-Key"].FirstOrDefault() ?? httpContext.Request.Query["apiKey"].FirstOrDefault(); var hasAccess = ValidateApiKey(apiKey); // 判断当前操作是否需要授权 var requiresAuth = context.MethodInfo.DeclaringType?.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any() == true || context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any(); // 无权限时标记操作隐藏 if (requiresAuth && !hasAccess) { operation.Extensions.Add("x-hidden", true); } } private bool ValidateApiKey(string apiKey) { return !string.IsNullOrEmpty(apiKey) && apiKey == "你的有效API密钥"; } }
5. 修改Swagger UI授权行为,触发页面刷新
默认Swagger UI的「Authorize」按钮不会刷新页面,需自定义脚本修改其行为,让用户输入密钥后自动刷新页面以加载过滤后的文档:
步骤1:配置Swagger UI注入自定义脚本
app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "你的API V1"); // 注入自定义授权脚本 c.InjectJavascript("/swagger-ui/custom-auth.js"); });
步骤2:创建自定义脚本文件
在wwwroot/swagger-ui目录下创建custom-auth.js:
document.addEventListener('DOMContentLoaded', function() { const authorizeBtn = document.querySelector('.authorize-wrapper button'); if (authorizeBtn) { authorizeBtn.addEventListener('click', function() { // 延迟执行,确保Swagger已保存授权信息 setTimeout(() => window.location.reload(), 500); }); } });
注意事项
- 动态生成文档会带来一定性能开销,生产环境建议根据API密钥添加文档缓存逻辑,减少重复生成。
- API密钥建议通过Header传递,避免暴露在URL查询参数中。
- 若使用Swashbuckle.AspNetCore新版本,需注意API变动,及时调整过滤器实现。
内容的提问来源于stack exchange,提问作者Formentz
相关产品推荐
相关产品推荐

