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

React中基于用户活跃状态的Token刷新与注销处理

实现基于用户活跃状态的Token刷新与清除逻辑

以下是修改后的完整代码,完全满足「仅用户活跃时每小时刷新Token,无活跃则清除Token」的需求:

import { useState, useEffect, useCallback } from 'react';
import useAuthStore from './path-to-your-auth-store'; // 替换为你的状态存储路径
import AuthenticationService from './path-to-authentication-service'; // 替换为你的认证服务路径
import CookieService from './path-to-cookie-service'; // 替换为你的Cookie工具路径

const App = () => {
  const [lastActiveTime, setLastActiveTime] = useState(Date.now());
  const [refreshTimerId, setRefreshTimerId] = useState(null);
  const [inactivityTimerId, setInactivityTimerId] = useState(null);

  // 把原回调式的refresh接口封装为Promise,简化异步逻辑
  const refreshTokenPromise = useCallback(() => {
    return new Promise((resolve, reject) => {
      AuthenticationService.refresh(null, resolve, reject);
    });
  }, []);

  // 核心Token刷新逻辑
  const refreshToken = useCallback(async () => {
    try {
      const { isLoggedIn } = useAuthStore.getState();
      if (isLoggedIn) {
        const response = await refreshTokenPromise();
        CookieService.set(activeAccount, response.data);
      }

      // 只有用户1小时内有活跃记录,才设置下一次刷新
      const now = Date.now();
      if (now - lastActiveTime < 1000 * 60 * 60) {
        const newTimerId = setTimeout(refreshToken, 1000 * 60 * 60);
        setRefreshTimerId(newTimerId);
      } else {
        setRefreshTimerId(null);
      }
    } catch (error) {
      console.error('Token刷新失败:', error);
      setRefreshTimerId(null);
    }
  }, [lastActiveTime, refreshTokenPromise]);

  // 启动刷新定时器
  const startRefreshInterval = useCallback(() => {
    const timerId = setTimeout(refreshToken, 1000 * 60 * 60);
    setRefreshTimerId(timerId);
  }, [refreshToken]);

  // 用户活跃事件处理:更新活跃时间、重置不活跃检测
  const handleUserActivity = useCallback(() => {
    setLastActiveTime(Date.now());

    // 清除之前的不活跃检测定时器
    if (inactivityTimerId) {
      clearTimeout(inactivityTimerId);
    }

    // 设置新的不活跃检测:1小时无操作则清除Token
    const newInactivityTimer = setTimeout(() => {
      const { isLoggedIn, setIsLoggedIn } = useAuthStore.getState();
      if (isLoggedIn) {
        CookieService.remove(activeAccount);
        setIsLoggedIn(false); // 同步更新全局登录状态
      }
      // 终止刷新定时器
      if (refreshTimerId) {
        clearTimeout(refreshTimerId);
        setRefreshTimerId(null);
      }
    }, 1000 * 60 * 60);
    setInactivityTimerId(newInactivityTimer);

    // 若未启动刷新定时器,立即启动
    if (!refreshTimerId) {
      startRefreshInterval();
    }
  }, [inactivityTimerId, refreshTimerId, startRefreshInterval]);

  useEffect(() => {
    const { isLoggedIn } = useAuthStore.getState();

    // 监听全局鼠标、键盘事件,捕获用户活跃行为
    window.addEventListener('mousemove', handleUserActivity);
    window.addEventListener('keydown', handleUserActivity);

    // 初始化时:若已登录,启动不活跃检测和刷新定时器
    if (isLoggedIn) {
      const initialInactivityTimer = setTimeout(() => {
        const { setIsLoggedIn } = useAuthStore.getState();
        CookieService.remove(activeAccount);
        setIsLoggedIn(false);
      }, 1000 * 60 * 60);
      setInactivityTimerId(initialInactivityTimer);
      startRefreshInterval();
    }

    // 组件卸载时清理所有定时器和事件监听
    return () => {
      window.removeEventListener('mousemove', handleUserActivity);
      window.removeEventListener('keydown', handleUserActivity);
      if (refreshTimerId) clearTimeout(refreshTimerId);
      if (inactivityTimerId) clearTimeout(inactivityTimerId);
    };
  }, [handleUserActivity, isLoggedIn, startRefreshInterval, refreshTimerId, inactivityTimerId]);

  return null;
};

export default App;

关键逻辑说明

  • 用户活跃跟踪:通过监听全局mousemove和keydown事件,实时更新用户最后活跃时间,每次活跃都会重置不活跃检测定时器
  • Token刷新控制:仅当用户1小时内有活跃记录时,才会维持刷新定时器;若用户超过1小时无操作,刷新定时器自动终止,不再调用刷新API
  • 不活跃Token清除:用户连续1小时无操作时,自动清除Token并同步更新全局登录状态,同时终止所有相关定时器
  • API适配:将原回调式的刷新接口封装为Promise,用async/await简化异步代码,提升可读性和可维护性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 09:07:54