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

React应用(Axios/Redux/React Router)中Auth0访问令牌过期检查方案

检查Auth0访问令牌过期的最佳实践(React + Axios + Redux + React Router)

方案对比与落地建议

针对你的技术栈,下面拆解两种方案的优劣,并给出可落地的实现思路:

1. Axios请求拦截器方案(优先推荐)

这种方式属于按需检查,只有在发起API请求时才验证令牌,不会浪费不必要的资源,是业务场景中最常用的方案。

实现思路:

  • 在Axios实例中添加请求拦截器,每次请求前从Redux或本地存储取出Auth0令牌
  • 用jwt-decode解码令牌,获取exp字段(过期时间戳,单位秒)
  • 对比当前时间戳(Date.now() / 1000)与exp,若当前时间≥过期时间,触发自动登出流程
  • 拦截过期请求,避免无效调用;令牌有效则正常添加请求头发送请求

代码示例:

import axios from 'axios';
import jwtDecode from 'jwt-decode';
import { useDispatch } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import { logoutUser } from '../redux/slices/authSlice';

// 创建全局Axios实例
const apiClient = axios.create({ baseURL: '/api' });

// 请求拦截器
apiClient.interceptors.request.use(
  (config) => {
    const dispatch = useDispatch();
    const navigate = useNavigate();
    const token = localStorage.getItem('auth0_access_token'); // 或从Redux state获取

    if (token) {
      try {
        const decodedToken = jwtDecode(token);
        const currentTime = Date.now() / 1000;

        if (decodedToken.exp <= currentTime) {
          // 令牌过期,执行登出
          dispatch(logoutUser());
          navigate('/login');
          return Promise.reject(new Error('Token expired'));
        }

        // 令牌有效,添加到请求头
        config.headers.Authorization = `Bearer ${token}`;
      } catch (err) {
        // 解码失败直接登出
        dispatch(logoutUser());
        navigate('/login');
        return Promise.reject(new Error('Invalid token'));
      }
    }
    return config;
  },
  (error) => Promise.reject(error)
);

export default apiClient;

2. 定时检查方案(补充场景)

这种方式适合处理用户长时间无操作的场景,能提前发现令牌过期并自动登出,提升安全性,但会消耗少量资源。

实现思路:

  • 在App根组件或Auth高阶组件中设置定时器(建议30-60秒一次)
  • 每次定时器触发时,检查令牌是否过期
  • 过期则执行登出流程,并立即清除定时器避免重复执行

代码示例:

import { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import jwtDecode from 'jwt-decode';
import { logoutUser } from '../redux/slices/authSlice';

const TokenExpiryChecker = () => {
  const { accessToken } = useSelector(state => state.auth);
  const dispatch = useDispatch();
  const navigate = useNavigate();

  useEffect(() => {
    let checkInterval;
    if (accessToken) {
      checkInterval = setInterval(() => {
        const decodedToken = jwtDecode(accessToken);
        const currentTime = Date.now() / 1000;

        if (decodedToken.exp <= currentTime) {
          dispatch(logoutUser());
          navigate('/login');
          clearInterval(checkInterval);
        }
      }, 30000); // 每30秒检查一次
    }

    // 组件卸载时清除定时器
    return () => clearInterval(checkInterval);
  }, [accessToken, dispatch, navigate]);

  return null; // 无UI渲染,仅做逻辑处理
};

export default TokenExpiryChecker;

最佳实践:两种方案结合

实际项目中建议同时使用:

  • Axios拦截器:确保所有API请求不会携带过期令牌,避免请求失败
  • 定时检查:处理用户长时间停留在页面无操作的场景,自动登出提升体验

自动登出核心逻辑

无论用哪种方案,登出都需要完成以下步骤:

  1. 调用Auth0的登出接口(清除Auth0端会话)
  2. 清除Redux中存储的用户信息与令牌
  3. 清除本地存储/会话存储中的令牌
  4. 通过React Router跳转到登录页

Redux Auth Slice示例:

import { createSlice } from '@reduxjs/toolkit';

const authSlice = createSlice({
  name: 'auth',
  initialState: {
    accessToken: null,
    userProfile: null,
  },
  reducers: {
    logoutUser: (state) => {
      // 清除本地存储
      localStorage.removeItem('auth0_access_token');
      localStorage.removeItem('auth0_id_token');
      // 清除Redux状态
      state.accessToken = null;
      state.userProfile = null;
      // 跳转到Auth0登出页面清除会话
      window.location.href = `${process.env.REACT_APP_AUTH0_DOMAIN}/v2/logout?client_id=${process.env.REACT_APP_AUTH0_CLIENT_ID}&returnTo=${window.location.origin}/login`;
    },
  },
});

export const { logoutUser } = authSlice.actions;
export default authSlice.reducer;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 20:08:24