AngularJS+SpringMVC SSO场景下CORS导致登出/会话失效无法跳转问题
问题根因说明
你遇到的CORS错误核心是两个原因:
- 会话无效时,后端直接返回302重定向到SSO登录域名,浏览器发送AJAX请求时会自动跟随重定向,跨域请求目标SSO域名没有配置允许当前应用域名的CORS规则,直接被浏览器同源策略拦截,不会走到你写的响应拦截器逻辑
- 前端AJAX请求默认没有携带Cookie,后端无法正确识别会话状态,也会触发无效会话逻辑
修复步骤
第一步:后端SpringMVC 5.x 配置调整
1. 全局CORS配置
新增CORS配置类,允许前端域名跨域访问、携带凭证:
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 替换为你实际前端部署的域名,不要用*,否则无法开启凭证携带 .allowedOrigins("http://你前端应用的域名:端口") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }
2. 修改会话拦截逻辑,禁止AJAX请求返回302
调整你的SSO会话拦截器/过滤器逻辑:如果是AJAX请求(请求头带X-Requested-With: XMLHttpRequest),会话无效时直接返回401状态码,不要重定向到SSO登录页,只有普通页面请求才返回302重定向。
// 会话拦截器示例逻辑 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (会话无效) { String xRequestedWith = request.getHeader("X-Requested-With"); if ("XMLHttpRequest".equals(xRequestedWith)) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return false; } else { // 普通页面请求,正常重定向到SSO登录页 response.sendRedirect("http://login.boshiftdev.com/app/ui/login.jsp"); return false; } } return true; }
3. Tomcat可选配置
如果使用Tomcat内置的CORS过滤器,需要在web.xml中配置允许凭证、指定允许的域名,不要用通配符。
第二步:前端AngularJS代码调整
1. 全局配置$http携带凭证
在应用配置块开启withCredentials,保证AJAX请求自动携带Cookie:
TestApp.config(function($httpProvider) { $httpProvider.defaults.withCredentials = true; // 统一添加AJAX请求标识,方便后端判断 $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; });
2. 修正响应拦截器逻辑
TestApp.factory('respInterceptor', function($location, $window, $cookies) { return { response: function(resp) { return resp; }, responseError : function(error) { console.log(" Error >>> : "+error.status ) if(error.status == 401) { // 修正原代码Cookie名拼写错误 $cookies.remove('JSESSIONID'); console.log("invalid session"); // 直接跳转登录页,不会触发跨域 window.location.href = "http://login.boshiftdev.com/app/ui/login.jsp"; } return Promise.reject(error); } }; }) // 注册拦截器 TestApp.config(function($httpProvider) { $httpProvider.interceptors.push('respInterceptor'); });
3. 修正登出逻辑
$scope.logout = function() { $cookies.remove('JSESSIONID'); console.log("logout"); $http({ method: 'POST', url: contextURL+'/logout', headers: {'Content-Type': 'application/json'}, params: {data: $rootScope.userSession } }).then(function successCallback(response) { $rootScope.userSession = null; window.location.href = "http://login.boshiftdev.com/app/ui/login.jsp"; }, function errorCallback(response) { $rootScope.userSession = null; window.location.href = "http://login.boshiftdev.com/app/ui/login.jsp"; console.error('登出请求失败'); }); }
效果验证
调整后会话无效时后端直接返回401,不会触发跨域重定向,前端拦截器收到401后主动跳转到SSO登录页,即可解决CORS报错问题。
内容的提问来源于stack exchange,提问作者Wen
相关产品推荐
相关产品推荐

