如何让Chrome在HTTP POST后遵循跨域302 Location重定向?
场景说明
我基于.NET 6搭建ASP.NET MVC应用,用OpenID Connect对接外部认证提供商做身份校验。现在遇到一个问题:执行账户关闭的POST请求后,服务器返回了指向跨域认证地址的302响应,但Chrome完全不执行重定向。
POST端点(无法正常重定向)
[HttpPost("close-account")] public async Task<IActionResult> CloseAccount() { // 账户已成功关闭,但浏览器未触发跨域重定向 var properties = new AuthenticationProperties { RedirectUri = "..." }; return SignOut(properties, "Cookies", "OpenIdConnect"); }
这个端点通过标准HTML <form> 和 <button> 提交POST请求,未使用JavaScript。
通过Chrome开发者工具确认:服务器返回了正确的302 Found响应,Location头指向跨域的OIDC登出URL(比如https://oidc.myauthenticationprovider.com/logout?....),但浏览器完全忽略该重定向。
GET端点(正常工作)
相同逻辑用GET请求就能正常触发跨域重定向:
[HttpGet("sign-out")] public async Task<IActionResult> SignOut() { // 此操作可正常跳转到跨域认证提供商页面 var properties = new AuthenticationProperties { RedirectUri = "..." }; return SignOut(properties, "Cookies", "OpenIdConnect"); }
已尝试的无效操作
我试过以下CORS相关设置,但均未解决问题:
- 应用启动时通过
services.AddCors添加目标跨域源 - 手动给关闭账户页面的GET请求和POST响应添加
Access-Control-Allow-Origin头
当前用户体验:点击按钮后账户已关闭,但页面无任何跳转,完全没反应。
核心原因
这是浏览器的同源安全策略限制:当普通表单POST请求的响应是跨域302时,浏览器不会自动执行重定向(防止CSRF类攻击),而GET请求不受此限制。
可行解决办法
方案1:改为GET请求(最简单)
如果业务允许,直接将close-account改为GET端点:
[HttpGet("close-account")] public async Task<IActionResult> CloseAccount() { // 先执行账户关闭逻辑 // ... var properties = new AuthenticationProperties { RedirectUri = "..." }; return SignOut(properties, "Cookies", "OpenIdConnect"); }
同时把页面的<form>方法改为GET,或者直接用链接按钮触发。
方案2:同域中转重定向(保留POST的前提下)
如果必须用POST(比如防止误触发),可以分两步实现:
- POST请求完成账户关闭后,先重定向到同域的GET端点
- 由这个同域端点触发到OIDC提供商的跨域重定向
代码示例:
[HttpPost("close-account")] public async Task<IActionResult> CloseAccount() { // 执行账户关闭逻辑 // ... // 先跳转到同域的中转端点 return RedirectToAction("TriggerOidcSignOut"); } [HttpGet("trigger-oidc-signout")] public async Task<IActionResult> TriggerOidcSignOut() { var properties = new AuthenticationProperties { RedirectUri = "..." }; return SignOut(properties, "Cookies", "OpenIdConnect"); }
方案3:JavaScript手动处理重定向
如果不想修改后端逻辑,可以用AJAX提交POST请求,在回调中手动读取Location头跳转:
document.getElementById('closeAccountForm').addEventListener('submit', async (e) => { e.preventDefault(); const form = e.target; const response = await fetch(form.action, { method: 'POST', credentials: 'include', body: new FormData(form) }); if (response.redirected) { window.location.href = response.url; } else { // 处理错误场景 } });
注:这种方式是同域AJAX请求,一般不需要额外配置CORS。
为什么CORS设置无效?
因为这不是AJAX/Fetch的跨域请求问题,而是浏览器对普通表单POST后跨域重定向的安全限制,CORS头仅对AJAX请求生效,对表单提交后的重定向不产生作用,所以之前的CORS配置完全没用。
内容的提问来源于stack exchange,提问作者bgs264

