Spring Boot+React结合Spring Security、JWT时会话超时跳转与前端报错处理
问题根因
你当前项目配置了SessionCreationPolicy.STATELESS,采用完全无状态的JWT认证模式,不依赖服务端的HttpSession存储用户状态,因此web.xml中的<session-config>超时配置、invalidSessionURL会话无效跳转配置均不会生效。你之前配置invalidSessionURL后直接跳转的原因也在于此:无状态模式下不会创建Session,所有请求默认都没有有效会话,触发了跳转规则。
后端改造步骤
- 首先删除
web.xml中无用的<session-config>配置,无需再配置服务端会话超时 - 生成JWT令牌时必须设置
exp过期声明,自定义超时时间(比如1小时) - 改造Spring Security的异常处理逻辑,认证失败(令牌过期、无效、未携带)时统一返回401状态码,不要做服务端跳转,适配前后端分离架构:
@Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.csrf().disable().authorizeRequests() .antMatchers(HttpMethod.GET, "/index*", "/static/**", "/*.js", "/*.json", "/*.ico", "/*.png") .permitAll().antMatchers("/resources/**", "/login", "/", "/actuator").permitAll() .antMatchers("/authenticate/**", "/identity/**").permitAll() .anyRequest().authenticated() .and().cors() .and() // 新增认证失败入口,统一返回401 .exceptionHandling().authenticationEntryPoint((request, response, authException) -> { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setCharacterEncoding("UTF-8"); response.getWriter().write("令牌已过期或无效,请重新登录"); }) .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); }
- 改造
JWTAuthenticationFilter,解析JWT时如果抛出ExpiredJwtException(令牌过期)、MalformedJwtException(令牌格式错误)等异常时,直接返回上述401响应即可。
React前端改造步骤
1. 全局请求拦截处理
封装全局请求工具(以axios为例),添加响应拦截器,只要收到后端返回的401状态码,立即清空本地存储的JWT和用户信息,跳转登录页:
import axios from 'axios'; const request = axios.create({ baseURL: process.env.REACT_APP_API_BASE_URL }); // 响应拦截器 request.interceptors.response.use( (res) => res, (err) => { if (err.response?.status === 401) { // 清空本地缓存的认证信息 localStorage.removeItem('jwt_token'); localStorage.removeItem('user_info'); // 跳转登录页 window.location.replace('/login'); } return Promise.reject(err); } ); export default request;
所有需要鉴权的接口都用这个封装后的request工具发起请求,即可自动处理超时后的报错和跳转。
2. 主动超时感知(可选)
如果需要实现用户停留在页面不发起请求也能自动超时跳转,可以在登录成功拿到JWT后,解析令牌中的exp过期时间,设置定时器主动触发跳转:
// 登录成功获取token后执行 const token = '接口返回的jwt令牌'; localStorage.setItem('jwt_token', token); // 解析JWT payload const payload = JSON.parse(atob(token.split('.')[1])); // 过期时间转毫秒 const expireTime = payload.exp * 1000; const now = Date.now(); const delay = expireTime - now; if (delay > 0) { // 到期自动退出 setTimeout(() => { localStorage.removeItem('jwt_token'); window.location.replace('/login'); }, delay); } else { // 令牌已过期直接退出 localStorage.removeItem('jwt_token'); window.location.replace('/login'); }
3. 路由守卫拦截(可选)
给React路由添加守卫逻辑,跳转鉴权路由前先判断本地是否存在有效JWT,不存在直接拦截跳转登录页,避免用户手动输入地址进入需要权限的页面。
内容的提问来源于stack exchange,提问作者Hitesh Kumar
相关产品推荐
相关产品推荐

