如何在Spring Security+AngularJS中保持登录?刷新登出问题求解
解决浏览器刷新后自动登出问题的详细思路
我来帮你一步步排查这个JWT+AngularJS项目里的刷新登出问题,这个场景其实挺常见的,咱们从几个核心关键点入手:
一、先调整请求头设置的时机,别在控制器里搞!
你现在在home.js里设置$http.defaults.headers.common['Authorization']的时机太晚了——刷新页面后,AngularJS的模块初始化是有顺序的,控制器代码(比如home.js里的逻辑)往往是在路由跳转完成后才执行,这时候第一个请求早就发出去了,根本没带上Authorization头,后端自然判定你未授权,直接触发登出。
正确的姿势是用HTTP拦截器,每次请求前自动从$sessionStorage里拿token并塞进请求头,不管页面怎么刷新都能生效:
// 先创建一个拦截器工厂 angular.module('yourApp').factory('authInterceptor', ['$sessionStorage', function($sessionStorage) { return { request: function(config) { // 检查sessionStorage里有没有有效token,记得加Bearer前缀(大部分JWT后端都要求这个格式) if ($sessionStorage.loginSession) { config.headers['Authorization'] = 'Bearer ' + $sessionStorage.loginSession; } return config; } }; }]); // 然后在模块配置里注册这个拦截器 angular.module('yourApp').config(['$httpProvider', function($httpProvider) { $httpProvider.interceptors.push('authInterceptor'); }]);
这样不管是页面刷新还是正常跳转,所有请求都会自动带上token,不会因为初始化顺序掉链子。
二、检查JWT本身和后端配置是否匹配
- 先确认token没过期:刷新页面后,打开浏览器开发者工具→Application→Session Storage,找到
loginSession的值,然后用控制台的atob()解析token的payload部分(比如atob('token的中间段')),看看exp字段对应的时间是不是已经过期了。如果token过期,后端肯定会拒绝请求,这时候得加个token刷新的逻辑。 - 后端是否正确识别Authorization头:看看Spring Security的JWT过滤器配置,是不是正确读取了Authorization头里的token,尤其是有没有处理
Bearer前缀。比如后端过滤器里应该有类似这样的代码:
// Spring Security JWT过滤器示例片段 public class JwtAuthenticationFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String authHeader = request.getHeader("Authorization"); // 必须检查头是否存在,且以Bearer开头 if (authHeader != null && authHeader.startsWith("Bearer ")) { String token = authHeader.substring(7); // 去掉Bearer前缀拿纯token // 接下来解析token、验证有效性、把认证信息存入SecurityContext } filterChain.doFilter(request, response); } }
如果后端没处理前缀,或者头的名称写错了,哪怕前端传了token,后端也认不出来,照样会返回未授权。
三、给路由加个"门卫",刷新时先验证身份
刷新页面后,AngularJS的路由会重新加载,这时候得在路由跳转前先确认token是否有效,别直接跳登录页:
给需要授权的路由加个resolve属性,在页面加载前先发起一个验证请求(比如后端的/api/user/me接口,用来返回当前用户信息),确认token有效再加载页面:
angular.module('yourApp').config(['$routeProvider', function($routeProvider) { $routeProvider .when('/home', { templateUrl: 'home.html', controller: 'HomeController', resolve: { auth: ['$http', '$sessionStorage', '$location', function($http, $sessionStorage, $location) { // 先检查sessionStorage里有没有token if (!$sessionStorage.loginSession) { $location.path('/login'); return; } // 发起验证请求,确认token能被后端识别 return $http.get('/api/user/me') .catch(function() { // 验证失败,清掉无效token跳登录 delete $sessionStorage.loginSession; $location.path('/login'); }); }] } }); }]);
这样刷新页面时,路由会先做身份验证,有效就继续加载,无效才跳登录,避免误登出。
四、排查sessionStorage的存储问题
有时候可能是$sessionStorage.loginSession在刷新后没读取到:
- 刷新前后都在控制台敲
console.log($sessionStorage.loginSession),看看值是否存在。如果刷新后为空,说明登录时没把token正确存进sessionStorage,检查登录控制器里的代码:
$scope.login = function() { $http.post('/api/login', {username: $scope.username, password: $scope.password}) .then(function(response) { // 确保这里存的是后端返回的有效JWT token $sessionStorage.loginSession = response.data.token; }); };
- 还要确认你的模块已经注入了
ngStorage——$sessionStorage是这个第三方模块提供的,没注入的话它就是undefined,自然读不到token:
// 根模块依赖里必须包含ngStorage angular.module('yourApp', ['ngRoute', 'ngStorage']);
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

