贝利信息

如何在 JWT Token 过期时自动跳转至登录页

日期:2026-01-01 00:00 / 作者:心靈之曲

本文介绍一种基于 useeffect 和 settimeout 的可靠方案,用于监听 jwt token 过期时间,并在过期瞬间触发登出与路由跳转,避免手动轮询或错误的时间比较逻辑。

在 React 应用中,仅依赖客户端时间判断 JWT 是否过期(如在 中直接调用 jwt-decode)存在多个严重问题:

✅ 正确做法是:将 Token 过期监听提升至应用顶层(如 App.js),利用 useEffect + setTimeout 实现“精准倒计时登出” —— 即根据 exp 时间戳计算剩余毫秒数,设置一次性定时器,在到期时自动 dispatch logout 并导航至 /auth/login。

✅ 推荐实现(App.js 中)

// App.jsx
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import jwt_decode from 'jwt-decode';
import { logout } from './features/auth/authSlice';

function App() {
  const navigate = useNavigate();
  const dispatch = useDispatch();
  // 假设 token 存储在 auth.user.token 中(请按实际 state 结构调整)
  const token = useSelector((state) => state.auth.user?.token);

  useEffect(() => {
    if (!token) return;

    let timerRef = null;

    try {
      const decoded = jwt_decode(token);
      const expiryMs = decoded.exp * 1000; // exp 是秒级时间戳
      const nowMs = Date.now();
      const timeout = expiryMs - nowMs;

      const onExpire = () => {
        dispatch(logout()); // 触发异步登出请求(可选)
        navigate('/auth/login', { replace: true });
      };

      if (timeout > 0) {
        timerRef = setTimeout(onExpire, timeout);
      } else {
        // Token 已过期,立即登出跳转
        onExpire();
      }
    } catch (error) {
      console.warn('Invalid or missing JWT token:', error);
      dispatch(logout());
      navigate('/auth/login', { replace: true });
    }

    // 清理定时器(组件卸载或 token 变更时)
    return () => {
      if (timerRef) clearTimeout(timerRef);
    };
  }, [dispatch, navigate, token]);

  return (
    
      {/* 你的 Router 配置,例如  */}
    
  );
}

export default App;

⚠️ 关键注意事项

// ProtectedRoutes.jsx(精简安全版)
import { Navigate, Outlet } from 'react-router-dom';
import jwt_decode from 'jwt-decode';

export default function ProtectedRoutes() {
  const token = sessionStorage.getItem('token');

  if (!token) return ;

  try {
    const { exp } = jwt_decode(token);
    if (Date.now() >= exp * 1000) {
      sessionStorage.removeItem('token');
      return ;
    }
  } catch {
    sessionStorage.removeItem('token');
    return ;
  }

  return ;
}

通过顶层定时器 + 路由守卫双保险,即可实现平滑、可靠、用户体验友好的 Token 过期自动跳转机制。