发布到预生产环境后Swagger UI调用接口返回403 Forbidden问题求助
故障原因分析
- 全局安全要求导致Swagger自动携带无效认证头
你为Swagger全局配置了AddSecurityRequirement,所有接口(包括标记[AllowAnonymous]的登录接口)都会默认带上Authorization请求头。如果你之前在Swagger填充过过期/无效的JWT,或者首次访问未填授权信息时Swagger携带了格式错误的空Authorization头,ASP.NET Core的JWT认证中间件检测到请求携带无效认证凭证时,哪怕接口加了[AllowAnonymous],也会直接返回403错误。而Postman调用时不会主动携带多余的Authorization头,所以可以正常访问。 - 登录接口自带已登录拦截逻辑
你补充的测试中携带有效JWT调用登录接口仍然失败,大概率是登录接口内部做了校验:判断当前请求已经通过JWT认证(即用户已登录),直接返回403禁止重复登录。Postman调用时你没有携带JWT头,所以能正常触发登录逻辑。 - 预生产环境HTTPS重定向丢失POST请求体
你在非开发环境配置了app.UseHttpsRedirection(),如果预生产环境的Swagger UI访问地址用的是HTTP协议,POST请求触发HTTPS重定向时会返回301/302状态码,浏览器会自动将POST请求转为GET请求,同时丢失请求体,最终导致接口参数校验失败返回403。Postman调用时你直接用了HTTPS地址,不会触发重定向,所以访问正常。 - 全局防伪令牌校验拦截Swagger请求
如果你的项目全局配置了[ValidateAntiForgeryToken]特性,Swagger发送POST请求时不会自动携带防伪令牌对应的Cookie和请求头,会被防伪校验中间件拦截返回403,Postman如果关闭了防伪校验或者自动携带了对应凭证,就可以正常访问。 - 中间件顺序配置错误
如果你的UseAuthentication、UseAuthorization中间件的位置放在了UseSwagger、UseSwaggerUI之后,或者UseCors只在非开发环境启用但没有配置正确的跨域规则,也会导致预生产环境Swagger的POST请求被拦截。
对应解决方案
- 针对全局安全要求问题:修改Swagger配置,不要全局添加安全要求,改为只给需要认证的接口自动添加安全要求,配置代码如下:
services.AddSwaggerGen(c => { c.SwaggerDoc("v2", new OpenApiInfo { Title = "Services.WebApi", Version = "v2" }); var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath); var securitySchema = new OpenApiSecurityScheme { Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\".", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.Http, Scheme = "bearer", Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }; c.AddSecurityDefinition("Bearer", securitySchema); // 移除原来的全局AddSecurityRequirement调用,新增下面这行配置 c.OperationFilter<SecurityRequirementsOperationFilter>(); });
调整后标记了[AllowAnonymous]的接口不会被Swagger自动携带Authorization头。
- 针对登录接口已登录拦截问题:调整登录接口的逻辑,如果业务允许已登录用户重新登录就去掉拦截,否则在接口说明里标注已登录状态下调用会返回403即可。
- 针对HTTPS重定向问题:预生产环境统一用HTTPS地址访问Swagger UI,或者配置SwaggerUI强制指定接口请求用HTTPS协议:
app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v2/swagger.json", "Services.WebApi ASP NET Core 5 v2"); // 非开发环境强制指定HTTPS地址 if (!env.IsDevelopment()) { c.ConfigObject.AdditionalItems["servers"] = new[] { new { url = "https://你的预生产环境域名" } }; } });
- 针对全局防伪令牌问题:给登录接口添加
[IgnoreAntiforgeryToken]特性,或者排除Swagger相关路径的防伪校验。 - 针对中间件顺序问题:调整Configure方法的中间件顺序为正确顺序:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } // 通用中间件全局启用,不要只放在else分支 app.UseHttpsRedirection(); app.UseCors(); // 必须放在授权中间件之前 app.UseAuthentication(); app.UseAuthorization(); app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v2/swagger.json", "Services.WebApi ASP NET Core 5 v2")); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
内容的提问来源于stack exchange,提问作者Matthew Flynn
相关产品推荐
相关产品推荐

