ASP.NET Core 7中如何允许被CORS策略阻止的重定向?
问题原因
你遇到的CORS错误核心在于:浏览器对预检OPTIONS请求的限制——预检请求不允许被重定向。当你的API接口触发认证挑战返回302重定向到登录页时,浏览器会拦截这个重定向并抛出CORS错误,因为预检请求的响应必须是2xx状态码,不能是302。
你的测试场景里,/api/ITodosApi/getTodos接口触发了重定向到谷歌,而前端是AJAX请求,浏览器先发送OPTIONS预检请求,这个请求被重定向后就触发了报错。
解决步骤
1. 调整认证逻辑:区分AJAX请求与普通浏览器请求
对于AJAX请求(比如前端SPA的API调用),不要返回302重定向,而是返回401未授权状态码,让前端主动处理跳转;仅对普通浏览器的页面请求返回302重定向到登录页。
在ASP.NET Core的认证配置中,可以通过CookieAuthenticationEvents实现这个判断:
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(fun opts -> opts.Events.OnRedirectToLogin <- fun context -> // 判断是否是AJAX请求 if context.Request.Headers.ContainsKey("X-Requested-With") || context.Request.Headers.Accept.ToString().Contains("application/json") then // 返回401,让前端处理跳转 context.Response.StatusCode <- 401 Task.CompletedTask else // 普通请求,执行默认重定向逻辑 context.Response.Redirect(context.RedirectUri) Task.CompletedTask ) |> ignore
2. 修正CORS中间件的顺序
CORS中间件必须放在认证和授权中间件之前,否则预检请求会先被认证逻辑拦截重定向,导致CORS配置失效。调整代码顺序:
builder.Services.AddCors() |> ignore builder.Services.AddAuthentication(...) // 先配置认证服务 builder.Services.AddAuthorization(...) // 再配置授权服务 let app = builder.Build() // 中间件顺序必须遵循:UseCors -> UseAuthentication -> UseAuthorization -> UseEndpoints app.UseCors(fun opts -> opts.WithOrigins("http://localhost:8080") .AllowCredentials() .AllowAnyMethod() .AllowAnyHeader() |> ignore ) |> ignore app.UseAuthentication() |> ignore app.UseAuthorization() |> ignore app.UseEndpoints(fun endpoints -> endpoints.MapControllers() |> ignore ) |> ignore
3. 前端处理401状态码
当前端API请求收到401响应时,手动跳转到登录页(测试阶段可先跳转到谷歌,后续替换为Azure AD授权端点)。以Fable/Elmish为例:
// 示例:API调用的错误处理逻辑 let getTodos () = async { try let! todos = Http.get "/api/ITodosApi/getTodos" return Ok todos with | :? HttpException as ex when ex.StatusCode = 401 -> // 跳转到登录页 Browser.Dom.window.location.href <- "https://accounts.google.com/" return Error "未授权,请登录" | ex -> return Error ex.Message }
关键说明
- 预检请求是浏览器自动发送的OPTIONS请求,用于确认跨域请求是否被允许,这个请求不能被重定向,必须返回2xx状态码。
- 让AJAX请求返回401而非302,是SPA应用处理认证的标准模式,可彻底避免这类CORS冲突。
内容的提问来源于stack exchange,提问作者Marko Grdinić
相关产品推荐
相关产品推荐

