You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React路由变更时如何触发登出并校验JWT accessToken是否过期

如何在JWT accessToken过期时对用户执行登出操作?

需求背景

  • 现有的withRouter高阶组件路由监听逻辑仅在用户点击浏览器返回按钮时生效
  • 需要覆盖所有路由变更场景(包括点击页面内导航链接如「返回首页」的场景),检测到token过期时自动移除localStorage中存储的token并执行登出

原始代码

AuthVerify.js

import React, { useEffect } from "react";
import { withRouter } from "react-router-dom";

const parseJwt = (token) => {
  try {
    return JSON.parse(atob(token.split(".")[1]));
  } catch (e) {
    return null;
  }
};

const AuthVerify = (props) => {
  console.log(props);
  useEffect(() => {
    props.history.listen(() => {
      const token = localStorage.getItem("accessToken");
      if (token) {
        const decodedJWT = parseJwt(token);

        if (decodedJWT.exp * 1000 < Date.now()) {
          console.log("expired");
          props.logOut();
        }
      }
    });
  }, []);

  return <div></div>;
};

export default withRouter(AuthVerify);

App.js

import { Fragment } from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";

import AuthVerify from "../src/utils/AuthVerify";

import "./App.css";

import Home from "./pages/Home";
import Signup from "../src/pages/Signup";
import Login from "./pages/Login";
import Test from "./pages/Test";

const logOut = () => {
  localStorage.removeItem("accessToken");
  localStorage.removeItem("refreshToken");
};

function App() {
  return (
    <Fragment>
      <div className="App">
        <BrowserRouter>
          <Switch>
            <Route exact path="/" component={Home} />
            <PrivateRoute exact path="/test" component={Test} />
            <Route exact path="/register" component={Signup} />
            <Route exact path="/login" component={Login} />
          </Switch>
        </BrowserRouter>
      </div>
      <AuthVerify logOut={logOut} />
    </Fragment>
  );
}

export default App;

问题原因

withRouter注入的history实例依赖React Router的路由上下文,原始代码中<AuthVerify />被放在<BrowserRouter>组件外部,无法监听到通过Link/history.push等前端路由API触发的路由变更,仅能捕获浏览器前进后退触发的popstate事件。

修复方案

调整AuthVerify组件的放置位置,将其移入<BrowserRouter>内部,即可获取到全局统一的路由上下文,监听到所有路由变更事件:

import { Fragment } from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";

import AuthVerify from "../src/utils/AuthVerify";

import "./App.css";

import Home from "./pages/Home";
import Signup from "../src/pages/Signup";
import Login from "./pages/Login";
import Test from "./pages/Test";

const logOut = () => {
  localStorage.removeItem("accessToken");
  localStorage.removeItem("refreshToken");
  // 可补充登出后跳转登录页逻辑,如 window.location.href = '/login'
};

function App() {
  return (
    <Fragment>
      <div className="App">
        <BrowserRouter>
          <Switch>
            <Route exact path="/" component={Home} />
            <PrivateRoute exact path="/test" component={Test} />
            <Route exact path="/register" component={Signup} />
            <Route exact path="/login" component={Login} />
          </Switch>
          {/* 移入BrowserRouter内部,获取正确的路由上下文 */}
          <AuthVerify logOut={logOut} />
        </BrowserRouter>
      </div>
    </Fragment>
  );
}

export default App;

可选优化

可给全局请求拦截器添加token过期校验逻辑,在请求发送前先判断token是否过期,若过期直接执行登出逻辑,覆盖路由未变更时的接口请求场景。

效果演示

携带accessToken的测试页
accessToken过期后路由变更时跳转到登录页

内容的提问来源于stack exchange,提问作者Gourav Thakur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 08:06:04