求助:JWT令牌过期时自动跳转至登录页的实现方案
JWT令牌过期自动跳转登录页的实现方案与代码修复
现有代码的核心问题
- ProtectedRoutes.js未处理
token不存在的情况,直接调用jwt_decode会抛出错误;isAuthActive函数定义后未被使用,且用字符串格式的时间比较(toLocaleString)不可靠;当前仅判断token是否存在,未校验过期状态。 - 未结合后端接口的401状态码做全局处理,
token过期后接口返回错误时无法自动跳转。 - Redux状态与
sessionStorage的用户信息不同步,存在状态不一致问题。
一、修复ProtectedRoutes的认证校验逻辑
修改路由守卫,添加容错处理,用时间戳直接比较判断token是否过期:
import { Navigate, Outlet } from "react-router-dom"; import jwt_decode from "jwt-decode"; export default function ProtectedRoutes() { const checkTokenValidity = () => { const token = sessionStorage.getItem("token"); if (!token) return false; try { const decoded = jwt_decode(token); // 用时间戳数值比较,避免字符串格式差异导致的错误 const currentTimestamp = Date.now() / 1000; if (decoded.exp < currentTimestamp) { sessionStorage.removeItem("token"); sessionStorage.removeItem("user"); return false; } return true; } catch (error) { // 解码失败(如token篡改),清除无效数据 sessionStorage.removeItem("token"); sessionStorage.removeItem("user"); return false; } }; const isAuthenticated = checkTokenValidity(); return isAuthenticated ? <Outlet /> : <Navigate to="/auth/login" replace />; }
二、添加登录后的自动过期定时器(可选)
在登录成功后设置8小时定时器,到期自动执行登出,和后端token有效期对齐:
修改authSlice.js的login.fulfilled逻辑:
.addCase(login.fulfilled, (state, action) => { state.isSuccess = true; state.user = action.payload; sessionStorage.setItem("user", JSON.stringify(action.payload)); // 设置8小时后自动登出 const expiryTime = 8 * 60 * 60 * 1000; // 8小时转换为毫秒 setTimeout(() => { logout(); window.location.href = "/auth/login"; }, expiryTime); })
注意:页面刷新后定时器会失效,因此路由守卫的校验仍是核心逻辑,定时器仅作为补充。
三、全局请求拦截器处理后端401状态
添加axios拦截器,统一处理token过期后接口返回的401错误:
修改authService.js:
import axios from "axios"; // 创建axios实例 const api = axios.create({ baseURL: import.meta.env.VITE_BACKEND_STAGING_URL }); // 请求拦截器:自动携带token到请求头 api.interceptors.request.use((config) => { const token = sessionStorage.getItem("token"); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); // 响应拦截器:捕获401错误,清除数据并跳转登录页 api.interceptors.response.use( (response) => response, (error) => { if (error.response?.status === 401) { sessionStorage.removeItem("token"); sessionStorage.removeItem("user"); window.location.href = "/auth/login"; } return Promise.reject(error); } ); // 修改登录、登出函数使用api实例 const login = async (formData) => { const response = await api.post("/api/v1/auth/signin", formData); if (response.data) { const { token } = response.data; sessionStorage.setItem("token", token); } return response.data; }; const logout = async () => { const response = await api.post("/api/v1/auth/logout"); if (response.data) { sessionStorage.removeItem("token"); sessionStorage.removeItem("user"); } return response.data; }; export { login, logout, api };
四、同步Redux状态与sessionStorage
修改authSlice.js的初始状态和登出逻辑,确保状态与本地存储同步:
const initialState = { // 从sessionStorage读取用户信息,保持与token存储位置一致 user: sessionStorage.getItem("token") ? JSON.parse(sessionStorage.getItem("user")) : null, isLoading: false, isError: false, isSuccess: false, }; // 修改登出逻辑 .addCase(logout.fulfilled, (state) => { state.isSuccess = true; state.user = null; sessionStorage.removeItem("user"); });
内容的提问来源于stack exchange,提问作者user22125377
相关产品推荐
相关产品推荐

