Azure AD会话过期引发CORS问题求助
问题场景
我为应用实现了基于Azure AD的登录机制,Azure端配置为WEB平台,首次登录请求流程如下:
https://my-service-test2.com/api/signin?post_login_redirect_uri=https%3A%2F%2Fmy-ui-test2.com%2Fhomehttps://my-service-test2.com/oauth2/authorization/azurehttps://login.microsoftonline.com/<>/oauth2/v2.0/authorize?response_type=code&client_id=<>&scope=openid%20profile%20offline_access&state=<>&redirect_uri=https://my-service-test2.com/login/oauth2/code/&nonce=<>https://my-service-test2.com/login/oauth2/code/?code=<>&state=<>&session_state=<>https://my-ui-test2.com/home
首次登录完全正常,但会话30分钟过期后,调用https://my-service-test2.com/api/product/productDetails时触发重定向到Azure的授权地址,此时出现CORS错误:
Access to XMLHttpRequest at 'https://login.microsoftonline.com/<>/oauth2/v2.0/authorize?response_type=code&client_id=<>&scope=openid%20profile%20offline_access&state=<>&redirect_uri=https://my-service-test2.com/login/oauth2/code/&nonce=<>' (redirected from 'https://my-service-test2.com/api/product/productDetails') from origin 'https://my-ui-test2.com' 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.
问题原因
会话过期后,后端API检测到用户未授权,自动重定向到Azure AD的授权端点,但这个重定向是在AJAX请求中触发的。而Azure AD的授权端点不支持CORS,不会返回Access-Control-Allow-Origin头,浏览器因此拦截了这个跨域请求。
解决方法
方法1:前端主动处理未授权状态,用页面跳转替代AJAX请求
- 后端API在会话过期时,不要直接重定向到Azure授权地址,而是返回401 Unauthorized状态码,同时在响应头里带上需要跳转的登录地址(比如
Location: https://my-service-test2.com/api/signin?post_login_redirect_uri=当前页面的URL)。 - 前端在全局AJAX拦截器里捕获401状态码,读取响应头中的登录地址,用
window.location.href跳转到该地址完成重新登录。这种页面跳转属于浏览器正常行为,不会触发CORS检查。
方法2:配置静默刷新令牌(Silent Refresh)
- 利用Azure AD的
response_type=id_token token模式,或者通过refresh token实现静默刷新,在会话过期前自动获取新的令牌,避免触发重定向。 - 后端需要支持refresh token的存储与使用,前端在令牌即将过期时,通过隐藏iframe发起静默授权请求(请求目标是后端的授权接口,已配置CORS),拿到新令牌后更新本地存储,维持会话有效性。
方法3:调整后端的重定向逻辑,区分请求类型
- 后端判断请求类型:如果是普通页面请求(非AJAX),就重定向到登录页;如果是AJAX请求,直接返回401状态码,由前端处理跳转。
- 可以通过检查请求头中的
X-Requested-With: XMLHttpRequest或者Accept头来区分AJAX请求和普通页面请求。
内容的提问来源于stack exchange,提问作者Krishna

