.NET 6自定义认证中间件拦截Swashbuckle Swagger页面如何修复
问题描述
.NET 6 Minimal API 项目使用默认配置集成 Swagger/Swashbuckle 时功能正常,添加自定义 ApiKey 认证中间件后访问异常:
认证中间件默认对所有请求执行ApiKey校验逻辑,包含/swagger/index.html在内的Swagger相关页面、静态资源请求默认不会携带ApiKey请求头,会直接触发校验分支返回400错误,导致Swagger页面无法加载。
原有问题代码如下:Program.cs 中间件注册代码:
app.UseMiddleware<Auth>();
Auth.cs 中间件逻辑代码:
public async Task InvokeAsync(HttpContext context, RequestDelegate next) { if (!context.Request.Headers.ContainsKey("ApiKey")) { context.Response.StatusCode = StatusCodes.Status400BadRequest; await context.Response.WriteAsync("No ApiKey provided in headers"); } if (!Guid.TryParse(context.Request.Headers["ApiKey"], out var apiKey)) { context.Response.StatusCode = StatusCodes.Status400BadRequest; await context.Response.WriteAsync("Unable to parse the ApiKey"); } try { /* Look in DB for API Key yada yada yada */ } catch { context.Response.StatusCode = StatusCodes.Status401Unauthorized; await context.Response.WriteAsync("Unauthorized"); } await next(context); }
修复方案
原有代码存在两个核心问题:一是没有对Swagger相关路径做白名单放行,二是校验失败分支没有做请求短路,写入错误响应后依然会执行后续逻辑,可能出现多次写入响应的异常。按以下步骤修复即可:
- 在认证逻辑最开头添加Swagger路径白名单判断,所有匹配Swagger前缀的请求直接跳过认证,传递到后续中间件处理,默认Swagger路径前缀为
/swagger,判断时注意忽略大小写。 - 所有校验不通过的分支,在写入错误响应后直接return终止当前请求逻辑,不要继续执行后续校验和管道调用,避免响应冲突。
修复后的Auth.cs代码如下:
public async Task InvokeAsync(HttpContext context, RequestDelegate next) { // 放行所有Swagger相关请求,跳过ApiKey校验 if (context.Request.Path.StartsWithSegments("/swagger", StringComparison.OrdinalIgnoreCase)) { await next(context); return; } if (!context.Request.Headers.ContainsKey("ApiKey")) { context.Response.StatusCode = StatusCodes.Status400BadRequest; await context.Response.WriteAsync("No ApiKey provided in headers"); return; } if (!Guid.TryParse(context.Request.Headers["ApiKey"], out var apiKey)) { context.Response.StatusCode = StatusCodes.Status400BadRequest; await context.Response.WriteAsync("Unable to parse the ApiKey"); return; } try { /* 数据库校验ApiKey逻辑 */ } catch { context.Response.StatusCode = StatusCodes.Status401Unauthorized; await context.Response.WriteAsync("Unauthorized"); return; } await next(context); }
如果你自定义过Swagger的路由前缀,把代码中判断路径的
/swagger替换为实际配置的前缀即可。如果需要在Swagger页面调试接口时自动携带ApiKey,可以额外给Swashbuckle配置全局ApiKey请求头参数,不影响Swagger页面本身的加载逻辑。
内容的提问来源于stack exchange,提问作者Kevin
相关产品推荐
相关产品推荐

