带Authorize属性的.NET Core接口被AJAX调用时出现CORS问题如何解决?
该问题仅在AJAX请求场景下触发,核心原因是用户未完成身份验证时,.NET Core身份验证中间件会自动将请求重定向到Azure AD登录端点,AJAX请求不支持跨域重定向,且微软登录端点不会添加适配业务域名的CORS响应头,和常规接口CORS配置失效问题不属于同一类。
原始报错信息:
Access to XMLHttpRequest at 'https://login.microsoftonline.com/..........' (redirected from 'https://localhost:44352/home/getdata?id=1) from origin 'https://localhost:44352' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.中文含义:
来自源https://localhost:44352的请求尝试访问https://login.microsoftonline.com/......(由接口https://localhost:44352/home/getdata?id=1重定向而来)时被CORS策略阻止:预检请求未通过访问控制校验,目标资源没有返回Access-Control-Allow-Origin响应头。
- 方案1:修改身份验证配置,对AJAX请求返回401而非重定向
修改.NET Core服务端的身份验证配置,重写质询事件逻辑,判断为AJAX请求时直接返回401状态码,不触发重定向逻辑,示例代码(适用于.NET 6+):
// Program.cs 中配置JWT/ Azure AD身份验证时添加以下逻辑 builder.Services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options => { options.Events.OnChallenge = async context => { // 识别AJAX请求:带X-Requested-With请求头 或 接受JSON格式响应 if (context.Request.Headers.ContainsKey("X-Requested-With") || context.Request.Headers.Accept.Any(x => x.Contains("application/json"))) { context.Response.StatusCode = StatusCodes.Status401Unauthorized; context.HandleResponse(); return; } // 非AJAX请求走原有重定向逻辑 await context.Response.WriteAsync(string.Empty); }; });
配置后前端可捕获401状态码,自行实现跳转登录页等逻辑,不会触发跨域重定向导致的CORS报错。
- 方案2:前端请求携带有效身份凭证
若用户已完成登录,发送AJAX请求时主动携带身份验证信息即可避免被重定向:
Fetch API示例
fetch('https://localhost:44352/home/getdata?id=1', { method: 'GET', headers: { 'Authorization': `Bearer ${你的访问令牌}`, // JWT验证场景添加 'X-Requested-With': 'XMLHttpRequest' }, credentials: 'include' // Cookie身份验证场景添加 })
jQuery AJAX示例
$.ajax({ url: 'https://localhost:44352/home/getdata?id=1', type: 'GET', headers: { 'Authorization': 'Bearer ' + 你的访问令牌 }, xhrFields: { withCredentials: true } })
- 方案3:确认服务端CORS中间件顺序正确
CORS中间件必须注册在身份验证、授权中间件之前,否则请求被身份验证中间件拦截时不会带上CORS响应头,正确中间件顺序参考:
var app = builder.Build(); // 第一步注册CORS中间件 app.UseCors(policy => policy.WithOrigins("https://localhost:44352") // 替换为实际前端域名 .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials()); // 再注册身份验证、授权中间件 app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
内容的提问来源于stack exchange,提问作者Vaibhav Bhatt

