ASP.NET Core中CORS策略执行失败但请求仍返回200的问题
我在ASP.NET Core Web Api/ReactJS SPA的请求管道中配置了CORS,日志显示CORS策略配置正确,但非法跨域请求并未被拦截。比如用不在AllowedOrigins里的源发起POST请求时,日志输出如下:
2024-09-23 21:23:42.7074||INFO|Microsoft.AspNetCore.Cors.Infrastructure.CorsService|CORS policy execution failed.
2024-09-23 21:23:42.7074||INFO|Microsoft.AspNetCore.Cors.Infrastructure.CorsService|Request origin https://localhost:44498 does not have permission to access the resource.
2024-09-23 21:23:42.7074||INFO|Microsoft.AspNetCore.Routing.EndpointMiddleware|Executing endpoint 'TweetController.PostTweet (releaseplanb)'
但奇怪的是,该请求仍返回200状态码,服务器没拦截,响应头里也没有Access-Control-Allow-Origin。前端用React的Fetch发起请求。
更新测试:策略验证成功时会生成Access-Control-Allow-Origin头,Chrome开发者工具里能看到成功时有值,失败时为空,这部分是正常的。我预期浏览器会提示CORS失败,或者ASP.NET Core直接拒绝请求。
我的配置代码如下:
using Microsoft.Extensions.FileProviders; using NLog; using NLog.Web; var builder = WebApplication.CreateBuilder(args);//WebApplicationBuilder var logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger(); logger.Debug("init main"); builder.Logging.AddNLogWeb("nlog.config"); builder.Host.UseNLog(); builder.Services.AddCors(options => { options.AddDefaultPolicy(o=>o.WithOrigins("https://localhost:44497") .AllowAnyHeader() .AllowAnyMethod() .WithExposedHeaders("Access-Control-Allow-Origin")); }); builder.Services.AddControllers(); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); app.UseExceptionHandler("/Home/Error"); } else { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider( Path.Combine(app.Environment.ContentRootPath,"ClientApp")), RequestPath = "/StaticFiles" }); app.UseRouting(); app.UseCors(); app.UseAuthorization(); app.MapControllers(); //app.MapFallbackToFile("index.html"); app.Run();
问题原因
ASP.NET Core的CORS中间件默认逻辑是:仅在预检请求(OPTIONS)或带Origin头的简单请求中验证策略,但验证失败时不会主动终止请求流程,只是不添加CORS响应头。服务器仍会执行后续的接口逻辑(比如你的TweetController.PostTweet),所以会返回200状态码。而浏览器的CORS拦截是客户端行为——只要响应没有Access-Control-Allow-Origin头,浏览器会阻止前端JS读取响应内容,但不会改变服务器返回的状态码。
解决方法
要让服务器在CORS验证失败时直接拒绝请求,有两种可行方案:
方案1:修改CORS策略,启用强制拦截
在CORS策略配置中添加FailOnInvalidOrigin = true,强制验证失败时返回403:
builder.Services.AddCors(options => { options.AddDefaultPolicy(o => o .WithOrigins("https://localhost:44497") .AllowAnyHeader() .AllowAnyMethod() .WithExposedHeaders("Access-Control-Allow-Origin") .SetPreflightMaxAge(TimeSpan.FromHours(1)) // 启用验证失败时返回403 .WithOptions(policy => policy.FailOnInvalidOrigin = true)); });
方案2:自定义中间件拦截失败请求
在UseCors之后添加自定义中间件,检查CORS验证结果,失败则直接返回403:
app.UseCors(); // 新增自定义中间件 app.Use(async (context, next) => { var corsFeature = context.Features.Get<ICorsResultFeature>(); if (corsFeature?.CorsResult.Failed == true) { context.Response.StatusCode = StatusCodes.Status403Forbidden; await context.Response.WriteAsync("CORS验证失败,拒绝访问"); return; } await next(); }); app.UseAuthorization();
补充说明
- 如果你之前没看到浏览器的CORS错误提示,检查前端Fetch请求是否设置了
mode: 'cors'(默认值),如果设置成no-cors会绕过浏览器的CORS检查,导致看不到错误。 - 确保
UseCors的位置正确:必须在UseRouting之后、UseAuthorization之前,这点你的配置已经符合要求。
内容的提问来源于stack exchange,提问作者Charles Owen

