React+SpringBoot架构下如何通过后端JWT工具类完成前端JWT有效性校验
解决方案
一、后端修改(核心解决UserDetails获取问题)
你不需要额外把用户信息存入Cookie,直接注入已有的MyUserDetailsService即可拿到UserDetails参数,修改后的校验接口代码如下:
@Autowired private MyUserDetailsService myUserDetailsService; // returns the username @GetMapping("/authenticate") public ResponseEntity<?> validateHeaderToken() throws Exception { try { System.out.println("Attempting to validate token"); String token = request.getHeader("Authorization"); token = token.split("Bearer ")[1]; // 1. 从token中提取用户名 String username = jwtTokenUtil.extractUsername(token); // 2. 调用MyUserDetailsService查询数据库获取对应用户的UserDetails UserDetails userDetails = myUserDetailsService.loadUserByUsername(username); // 3. 调用全量校验方法完成完整校验 if (jwtTokenUtil.validateToken(token, userDetails)) { return ResponseEntity.ok(username); } else { throw new Exception("Expired or Invalid Token"); } } catch (Exception e) { // 所有异常(token非法、用户不存在、token过期等)统一返回401未授权 return ResponseEntity.status(401).build(); } }
上述代码逻辑可以覆盖所有校验场景:如果token是伪造的、对应用户已被删除、token过期都会校验失败返回401。
二、前端现有逻辑bug修复
你当前前端代码存在语法错误和逻辑缺陷,会导致校验失效,同步修改如下:
1. 修复AuthService的validateToken方法错误
原写法.then("did it")属于语法错误,不会返回接口真实响应,修改为:
validateToken() { console.log(" about to try validating"); return AxiosInstance.get("authenticate") .then(res => res.data) .catch((err) => { console.log(err); return null; }); }
2. 修复Axios实例Authorization头写死问题
原创建实例时直接读取localStorage的token,后续token更新后实例的请求头不会同步更新,改为用请求拦截器动态添加:
const AxiosInstance = axios.create({ baseURL: API_BASE_URL, }); // 请求拦截器:每次发请求前动态拼接Authorization头 AxiosInstance.interceptors.request.use(config => { const token = localStorage.getItem("token"); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, error => { return Promise.reject(error); });
3. 优化React组件校验逻辑
componentDidMount() { this._isMounted = true; const token = localStorage.getItem("token"); // 无token直接跳转登录 if (!token) { this.props.history.push("/login"); return; } AuthService.validateToken() .then((res) => { // 校验失败跳转登录 if (!res) { this.props.history.push("/login"); return; } // 校验通过再请求业务数据 return TicketService.getTickets(); }) .then((res) => { if (this._isMounted && res) { this.setState({ tickets: res.data }); } }); } componentWillUnmount() { this._isMounted = false; }
内容的提问来源于stack exchange,提问作者mcool
相关产品推荐
相关产品推荐

