Angular8+Jwt+DotNetCore2.1带[Authorize]的POST请求CORS报错求助
这个问题我之前踩过完全一样的坑,核心原因是预检请求(OPTIONS)被授权中间件提前拦截了,导致你的CORS配置根本没机会生效。让我一步步给你拆解问题和解决方法:
问题根源
你的登录请求属于「简单请求」(没有携带自定义Authorization头),浏览器会直接发送请求,此时CORS配置能正常返回响应头,所以请求没问题。但带Authorization头的请求属于「非简单请求」,浏览器会先自动发送一个OPTIONS预检请求,用来询问服务器是否允许该请求的头、方法和来源。
而ASP.NET Core的中间件是按顺序执行的,如果UseCors中间件的执行顺序在UseAuthorization之后,就会出现:
- OPTIONS预检请求没有携带token,被
[Authorize]拦截直接返回401 - 此时CORS中间件还没处理这个请求,所以不会返回
Access-Control-Allow-Origin等关键头 - 浏览器看到响应里没有CORS相关头,直接触发跨域错误,根本不会发送真正的POST请求,所以你的API方法永远不会被调用
解决方案步骤
1. 调整Startup.cs中间件顺序(最关键!)
在Configure方法里,必须把UseCors放在UseAuthorization和UseMvc之前,确保CORS中间件优先处理所有请求(包括预检请求)。
修改后的Configure方法示例:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // 第一步:启用CORS,必须在授权和MVC中间件之前 app.UseCors("Cors"); // 第二步:处理身份验证与授权 app.UseAuthentication(); app.UseAuthorization(); // 第三步:启用MVC app.UseMvc(); }
2. 简化CORS配置(可选)
你可以把CORS策略全局应用到所有控制器,不用在每个方法上重复加[EnableCors("Cors")],修改ConfigureServices里的配置:
public void ConfigureServices(IServiceCollection services) { services.AddHttpContextAccessor(); services.AddOptions(); services.Configure<AppSettings>(Configuration.GetSection("AppSettings")); // 注册CORS策略 services.AddCors(o => o.AddPolicy("Cors", builder => { builder.AllowAnyOrigin() .AllowAnyMethod() .AllowCredentials() .AllowAnyHeader(); })); // 全局应用CORS策略到MVC services.AddMvc(options => { options.EnableEndpointRouting = false; }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_1) .AddCors("Cors"); // 其他服务注册... services.AddScoped<UserRepository>(); services.AddScoped<PassengerRepository>(); var connection = getConnectionString(); services.AddDbContext<Context>(options => options.UseSqlServer(connection)); }
3. 移除前端多余的CORS头(重要!)
你的Angular写法2里添加了Access-Control-Allow-Origin等头,这些完全不需要前端设置——这些是服务器返回给浏览器的响应头,前端添加不仅没用,还可能干扰预检请求。直接保留写法1的简洁配置即可:
this.headers = new HttpHeaders({ 'Authorization': 'Bearer ' + JSON.parse(localStorage.getItem('currentUser')).token, 'Content-Type': 'application/json' }); return this.http.post<any>(`${environment.apiUrl}/api/manifest/add`, { name, surname, seat, flight }, { headers: this.headers }) .pipe(map(result => { return result; }));
4. 额外保障:让OPTIONS请求跳过授权验证
如果上面的步骤还没解决,可以添加一个全局过滤器,确保所有OPTIONS请求自动跳过授权检查:
public class AllowAnonymousForOptionsAttribute : Attribute, IAuthorizationFilter { public void OnAuthorization(AuthorizationFilterContext context) { if (context.HttpContext.Request.Method == HttpMethod.Options.Method) { context.Result = new OkResult(); } } }
然后在ConfigureServices的AddMvc里注册这个过滤器:
services.AddMvc(options => { options.Filters.Add(new AllowAnonymousForOptionsAttribute()); options.EnableEndpointRouting = false; }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_1) .AddCors("Cors");
验证方法
修改完成后,打开浏览器开发者工具的Network面板:
- 首先会看到一个OPTIONS请求发送到
/api/manifest/add,状态码应为200 - 随后会发送真正的POST请求,此时响应头里会包含
Access-Control-Allow-Origin,请求也会正常到达你的API方法
内容的提问来源于stack exchange,提问作者Diego Perez

