.NET Core 6自定义中间件复刻AllowCredentials()遇POST请求失效问题
问题分析与解决方案
问题根因
你的POST请求失效的核心原因:
- POST属于非简单请求,浏览器会先发
OPTIONS预请求验证跨域权限,这个预请求直接由UseCors中间件处理并返回响应,根本没走到你的自定义中间件,所以预请求响应里没有Access-Control-Allow-Credentials头,浏览器直接拦截了后续的实际POST请求。 - GET是简单请求,浏览器不会发预请求,直接走到自定义中间件添加了头,所以能正常工作。
- 你的
UseCors中间件顺序错误,放在了UseRouting之前,导致CORS无法正确结合路由信息处理策略。
修复步骤
1. 调整中间件顺序(必须先做)
把UseCors移到UseRouting之后、自定义中间件之前,这是ASP.NET Core CORS中间件的标准位置:
public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env) { FileLogger.LogInformation("Start Configure"); if (!env.IsDevelopment()) { app.UseHsts(); } app.UseHttpsRedirection(); app.UseForwardedHeaders(); FileLogger.LogInformation("Register Routing"); app.UseRouting(); // 修正:UseCors移到UseRouting之后 app.UseCors(allowSpecificOrigins); FileLogger.LogInformation("Register Foo Middleware"); app.UseMiddleware<FooMiddleware1>(); app.UseMiddleware<FooMiddleware2>(); app.UseMiddleware<FooMiddleware3>(); FileLogger.LogInformation("Register Endpoints"); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
2. 动态设置CORS Credentials(替代手动加头)
不要手动添加响应头,而是利用ASP.NET Core的CORS扩展机制动态控制Access-Control-Allow-Credentials,这样能同时覆盖预请求和实际请求:
步骤2.1:创建动态CORS策略提供者
public class DynamicCorsPolicyProvider : ICorsPolicyProvider { private readonly string _targetPolicyName; private readonly DefaultCorsPolicyProvider _innerProvider; public DynamicCorsPolicyProvider(string targetPolicyName, DefaultCorsPolicyProvider innerProvider) { _targetPolicyName = targetPolicyName; _innerProvider = innerProvider; } public async Task<CorsPolicy> GetPolicyAsync(HttpContext context, string policyName) { // 只处理我们定义的目标策略 if (policyName != _targetPolicyName) return await _innerProvider.GetPolicyAsync(context, policyName); // 获取基础策略 var policy = await _innerProvider.GetPolicyAsync(context, policyName); // 这里替换成你的foo条件判断逻辑 // 注意:预请求(OPTIONS)没有请求体,所以如果foo依赖请求体,要改用头/查询参数 bool foo = /* 你的条件判断,比如从context.Request.Headers/Query里取值 */; // 动态设置是否允许Credentials policy.SupportsCredentials = foo; return policy; } }
步骤2.2:注册动态提供者并修改CORS策略
在Startup.cs的ConfigureServices里,替换默认的CORS策略提供者,同时不要在基础策略里提前设置AllowCredentials():
// 定义策略名称常量 private const string allowSpecificOrigins = "AllowSpecificOrigins"; services.AddCors(options => { options.AddPolicy( allowSpecificOrigins, builder => { builder .AllowAnyHeader() .SetIsOriginAllowed(_ => true) .SetPreflightMaxAge(TimeSpan.FromDays(1)) .WithExposedHeaders("Content-Disposition", "X-Suggested-Filename", "Request-Id") .WithMethods(HttpMethod.Get.ToString(), HttpMethod.Post.ToString(), HttpMethod.Options.ToString()); // 不要加AllowCredentials(),交给动态提供者处理 }); }); // 替换默认的CORS策略提供者 services.AddSingleton<ICorsPolicyProvider>(sp => { var innerProvider = sp.GetRequiredService<DefaultCorsPolicyProvider>(); return new DynamicCorsPolicyProvider(allowSpecificOrigins, innerProvider); });
额外注意事项
- 如果你的
foo条件依赖请求体,预请求(OPTIONS)是没有请求体的,这时候需要把判断条件转移到请求头或查询参数中,否则预请求会无法正确获取foo值。 - 前端的
withCredentials = true要保持开启,同时确保请求的Origin在CORS策略允许范围内(你的SetIsOriginAllowed(_ => true)已经覆盖了所有Origin)。
内容的提问来源于stack exchange,提问作者Faraaz
相关产品推荐
相关产品推荐

