.NET Core 2.2 API对接Azure AD认证时遇CORS错误求助
看起来你遇到的核心问题不是普通的CORS配置错误,而是AJAX请求遇到302重定向到跨域登录页时被浏览器拦截的问题。让我一步步帮你拆解和解决:
问题本质
当未认证的前端AJAX请求访问带[Authorize]的API时,ASP.NET Core默认会返回302重定向到Azure AD登录页。但浏览器的CORS机制会拦截这个重定向的响应——因为重定向目标(login.microsoftonline.com)的响应没有包含你的前端域名的Access-Control-Allow-Origin头,所以浏览器直接阻止了这个跳转。
手动能打开登录页是因为直接导航不属于AJAX请求,不受CORS限制,但AJAX请求的重定向就会触发这个问题。
第一步:纠正前端请求的错误配置
你当前的fetch请求里加了错误的请求头:Access-Control-Allow-Origin和Access-Control-Allow-Headers是服务器返回给前端的响应头,前端请求时不需要设置这些,反而会触发不必要的OPTIONS预请求,甚至导致CORS校验失败。修改前端代码:
fetch('api/SampleData/WeatherForecasts', { method: "get", credentials: 'include' // 必须带上这个,因为Azure AD认证是基于Cookie的 })
第二步:让API返回401而非302重定向
对于AJAX请求,我们不需要返回302重定向,而是返回401未授权状态码,让前端自己处理登录跳转。在Startup.cs的ConfigureServices里修改Cookie认证的事件:
services.AddAuthentication(AzureADDefaults.AuthenticationScheme) .AddAzureAD(options => Configuration.Bind("AzureAd", options)) .AddCookie(options => { options.Events = new CookieAuthenticationEvents { OnRedirectToLogin = context => { // 判断当前请求是否是API/AJAX请求 bool isApiRequest = context.Request.Path.StartsWithSegments("/api") || context.Request.Headers["X-Requested-With"] == "XMLHttpRequest"; if (isApiRequest) { // 对于API请求,返回401而非重定向 context.Response.StatusCode = StatusCodes.Status401Unauthorized; return Task.CompletedTask; } // 非API请求(比如页面导航),正常重定向到登录页 context.Response.Redirect(context.RedirectUri); return Task.CompletedTask; } }; });
第三步:前端处理401状态并跳转登录
当下端返回401时,前端手动跳转到登录页(ASP.NET Core的OIDC中间件已经帮你准备好了登录路径/signin-oidc):
fetch('api/SampleData/WeatherForecasts', { method: "get", credentials: 'include' }) .then(response => { if (response.status === 401) { // 跳转到Azure AD登录页 window.location.href = '/signin-oidc'; } else { return response.json(); } }) .catch(error => console.error('请求出错:', error));
第四步:确保CORS配置正确
你的CORS配置位置基本正确,但要注意:
UseCors必须放在UseAuthentication之后,UseMvc之前,这样认证后的请求才能经过CORS校验。- 因为我们用了
credentials: 'include',所以CORS策略必须包含.AllowCredentials()——你当前的配置已经加了这个,没问题。 - 生产环境不要用
AllowAnyOrigin(),要指定你的前端域名(比如https://yourapp.azurewebsites.net),避免安全风险。
另外,控制器上的[EnableCors]如果没有指定策略名,会使用默认策略,你可以在ConfigureServices里注册一个默认策略:
services.AddCors(setup => { setup.AddDefaultPolicy(policy => { policy .AllowCredentials() .AllowAnyHeader() .AllowAnyMethod() .WithOrigins("https://localhost:44363"); // 生产环境替换成你的实际域名 }); });
额外检查点
- 确认Azure AD应用注册的重定向URI已经添加了
https://localhost:44363/signin-oidc(从你的服务器日志看已经配置了,但再确认一遍)。 - 多租户场景下
ValidateIssuer = false的配置是正确的,因为不同租户的Issuer会不一样。
这样修改后,前端就不会再遇到CORS拦截的问题,而是在未登录时主动跳转到Azure AD登录页,登录完成后再正常调用API。
内容的提问来源于stack exchange,提问作者Ivan Nifantyef

