如何在Swashbuckle的IDocumentFilter类中获取请求头?
关于IDocumentFilter中检查请求头的问题
我的代码实现
public class ShowDocumentationFilter : IDocumentFilter { [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] public class ShowDocumentationAttribute : Attribute { } void IDocumentFilter.Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer) { //如果请求不包含请求头,则执行以下操作: foreach (ApiDescription apiDescription in apiExplorer.ApiDescriptions) { if ((apiDescription.RelativePathSansQueryString().StartsWith("api/System/")) || (apiDescription.RelativePath.StartsWith("api/Internal/")) || (apiDescription.Route.RouteTemplate.StartsWith("api/OtherStuff/")) ) { swaggerDoc.paths.Remove("/" + apiDescription.Route.RouteTemplate.TrimEnd('/')); } } } }
问题
我希望将上述逻辑应用到我的端点上,但能否在这个ShowDocumentationFilter类中检查访问端点的请求是否包含特定请求头?
解答
首先明确:IDocumentFilter的Apply方法是在生成Swagger文档时执行的,并非处理实际接口请求的阶段,所以这个方法里没法直接获取当前的HTTP请求上下文,自然也没法直接检查请求头。
如果要实现「根据请求头决定是否显示指定Swagger文档」的需求,可以通过以下方式实现:
方案一:注入IHttpContextAccessor获取请求上下文
通过依赖注入拿到当前请求的上下文,就能判断请求头是否存在:
- 先在项目的启动配置(Startup.cs 或 Program.cs)中注册
IHttpContextAccessor:services.AddHttpContextAccessor(); - 修改过滤器类,注入
IHttpContextAccessor并添加请求头检查逻辑:
这种方式会在每次请求Swagger文档时,根据当前请求的头信息动态生成文档内容。public class ShowDocumentationFilter : IDocumentFilter { private readonly IHttpContextAccessor _httpContextAccessor; // 通过构造函数注入请求上下文访问器 public ShowDocumentationFilter(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] public class ShowDocumentationAttribute : Attribute { } void IDocumentFilter.Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer) { var httpContext = _httpContextAccessor.HttpContext; // 检查是否存在目标请求头,这里以"X-Allow-Internal-Docs"为例 var hasRequiredHeader = httpContext?.Request.Headers.ContainsKey("X-Allow-Internal-Docs") ?? false; // 仅当没有指定请求头时,才移除指定路径的文档 if (!hasRequiredHeader) { foreach (ApiDescription apiDescription in apiExplorer.ApiDescriptions) { var isInternalPath = apiDescription.RelativePathSansQueryString().StartsWith("api/System/") || apiDescription.RelativePath.StartsWith("api/Internal/") || apiDescription.Route.RouteTemplate.StartsWith("api/OtherStuff/"); if (isInternalPath) { var pathKey = "/" + apiDescription.Route.RouteTemplate.TrimEnd('/'); // 先判断键是否存在,避免抛出异常 if (swaggerDoc.paths.ContainsKey(pathKey)) { swaggerDoc.paths.Remove(pathKey); } } } } } }
方案二:使用中间件全局控制
如果需要更全局的权限控制,可以编写一个中间件,在请求Swagger文档接口时先检查请求头,不符合条件的直接返回禁止访问(如403状态码),不过这种方式的灵活性不如过滤器高。
内容的提问来源于stack exchange,提问作者Joe Defill
相关产品推荐
相关产品推荐

