如何为Swashbuckle Swagger UI路由绑定自定义Handler(非全局管道)
1. 避免全局注册Handler,仅绑定到Swagger UI路由
首先,移除你手动添加的SwaggerUI路由配置——因为EnableSwaggerUi已经自动注册了该路由,重复注册会导致路由匹配冲突,你的自定义Handler无法生效。
接下来,我们需要让Swagger UI的路由使用你的自定义Handler,同时保留Swashbuckle原本的UI处理逻辑,具体步骤如下:
步骤1:自定义DelegatingHandler,不提前设置InnerHandler
确保你的MyHandler继承自DelegatingHandler,并且不在构造函数中设置InnerHandler(Web API会在路由绑定阶段自动为其赋值,或者我们手动指定Swashbuckle的内置Handler作为InnerHandler):
public class MyHandler : DelegatingHandler { protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { // 在这里添加Swagger UI访问权限校验逻辑 var isAuthorized = CheckSwaggerAccessPermission(request); if (!isAuthorized) { return request.CreateResponse(HttpStatusCode.Unauthorized, "没有访问Swagger UI的权限"); } // 权限验证通过后,继续执行Swashbuckle的UI渲染逻辑 return await base.SendAsync(request, cancellationToken); } private bool CheckSwaggerAccessPermission(HttpRequestMessage request) { // 实现你的权限检查逻辑,比如验证请求中的认证信息 var authHeader = request.Headers.Authorization; return authHeader != null && authHeader.Scheme == "Bearer" && ValidateToken(authHeader.Parameter); } private bool ValidateToken(string token) { // 替换为你的Token验证逻辑 return true; } }
步骤2:手动注册Swagger UI路由并绑定自定义Handler
我们需要替换Swashbuckle自动注册的路由,改为手动注册并指定自定义Handler。先只启用Swagger文档(不自动注册UI路由),再手动添加UI路由:
// 仅启用Swagger文档,不自动注册UI路由 config.EnableSwagger(c => { c.SingleApiVersion("v1", "你的API名称"); // 其他Swagger文档配置... }); // 获取Swashbuckle内置的SwaggerUiHandler实例 var swaggerUiConfig = new SwaggerUiConfig(config); var swaggerUiHandler = new SwaggerUiHandler(config, swaggerUiConfig); // 手动注册Swagger UI路由,将自定义Handler作为外层处理 config.Routes.MapHttpRoute( name: "SwaggerUI", routeTemplate: "docsite/{*assetPath}", handler: new MyHandler { InnerHandler = swaggerUiHandler } );
这样,所有访问/docsite/路径下的请求都会先经过MyHandler的权限校验,通过后再传递给Swashbuckle的内置Handler处理UI渲染。
2. 解决OWIN认证时的DelegatingHandler错误
你遇到的"The 'DelegatingHandler' list is invalid because the property 'InnerHandler' of 'MyHandler' is not null."错误,是因为你可能将已经设置了InnerHandler的MyHandler实例添加到了全局MessageHandlers列表中。全局MessageHandlers中的DelegatingHandler不能提前设置InnerHandler,Web API会自动为全局Handler构建管道。
解决方法:
- 确保你没有执行
config.MessageHandlers.Add(new MyHandler { InnerHandler = ... })这类代码。 - 仅通过上述路由绑定方式使用
MyHandler,不要将其加入全局管道。
3. 验证路由匹配顺序
由于你的项目使用特性路由,需要确保手动注册的Swagger UI路由在特性路由之后映射(你已经做到了config.MapHttpAttributeRoutes()在前,再注册Swagger路由),这样特性路由会优先匹配,Swagger路由只会处理/docsite/开头的请求,不会影响其他API路由。
内容的提问来源于stack exchange,提问作者user3093582

