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

如何在Amplify中禁止自动刷新AccessToken并实现无活动超时登出

解决React + Amplify + Cognito无操作自动登出问题

核心问题分析

Amplify的Auth.currentSession方法会自动用RefreshToken刷新即将过期或已过期的AccessToken,导致你无法获取原始AccessToken的过期时间来判断用户是否无操作满1小时。要实现需求,需要绕过自动刷新的干扰,单独追踪用户活动状态和初始令牌过期时间。


解决方案步骤

1. 存储用户最后活动时间

监听用户的核心交互事件,每次触发时更新本地存储的最后活动时间,以此判断用户是否处于无操作状态。

// 在App根组件或全局布局组件中添加监听
useEffect(() => {
  const updateLastActivity = () => {
    localStorage.setItem('lastActivityTime', Date.now().toString());
  };

  // 监听常见用户交互事件
  window.addEventListener('click', updateLastActivity);
  window.addEventListener('keydown', updateLastActivity);
  window.addEventListener('scroll', updateLastActivity);

  return () => {
    // 组件卸载时移除监听
    window.removeEventListener('click', updateLastActivity);
    window.removeEventListener('keydown', updateLastActivity);
    window.removeEventListener('scroll', updateLastActivity);
  };
}, []);

2. 保存初始AccessToken过期时间

用户首次登录成功后,立即获取原始AccessToken的过期时间并存储到本地,避免后续自动刷新覆盖该值。

// 登录成功后执行(比如Auth.signIn的回调中)
const handleLoginSuccess = async () => {
  const userSession = await Auth.currentSession();
  // 存储初始AccessToken过期时间(转成毫秒)
  const initialAccessTokenExp = userSession.accessToken.payload.exp * 1000;
  localStorage.setItem('initialAccessTokenExp', initialAccessTokenExp);
  // 初始化最后活动时间
  localStorage.setItem('lastActivityTime', Date.now().toString());
};

3. 定时检查无操作超时

设置定时任务,定期对比当前时间、最后活动时间、初始AccessToken过期时间,满足条件则强制登出。

useEffect(() => {
  const checkInactivity = () => {
    const now = Date.now();
    const lastActivity = parseInt(localStorage.getItem('lastActivityTime') || '0', 10);
    const initialExp = parseInt(localStorage.getItem('initialAccessTokenExp') || '0', 10);
    const inactivityDuration = now - lastActivity;

    // 无操作满1小时,且当前时间已过初始AccessToken过期时间
    if (inactivityDuration >= 3600000 && now > initialExp) {
      Auth.signOut()
        .then(() => {
          // 清理存储的状态
          localStorage.removeItem('initialAccessTokenExp');
          localStorage.removeItem('lastActivityTime');
          setIsAuthenticated(false);
          // 可选:跳转到登录页
          window.location.href = '/login';
        })
        .catch(err => console.error('登出错:', err));
    }
  };

  // 每分钟检查一次,平衡性能与实时性
  const interval = setInterval(checkInactivity, 60000);
  return () => clearInterval(interval);
}, [setIsAuthenticated]);

4. 调整页面访问时的验证逻辑

每次页面加载时,先检查无操作超时状态,再执行IdToken验证:

const verifyUser = async () => {
  try {
    // 先检查无操作超时
    const now = Date.now();
    const lastActivity = parseInt(localStorage.getItem('lastActivityTime') || '0', 10);
    const initialExp = parseInt(localStorage.getItem('initialAccessTokenExp') || '0', 10);
    
    if (now - lastActivity >= 3600000 && now > initialExp) {
      await Auth.signOut();
      localStorage.clear();
      setIsAuthenticated(false);
      return;
    }

    // 正常执行IdToken验证
    const userSession = await Auth.currentSession();
    setIsAuthenticated(true);
    setAuth(userSession);
  } catch (err) {
    setIsAuthenticated(false);
  }
};

// 页面加载时触发验证
useEffect(() => {
  verifyUser();
}, []);

关键逻辑说明

  • 初始AccessToken过期时间:确保我们判断的是用户最后一次操作后是否经过1小时,而非Amplify自动刷新后的令牌有效期。
  • 用户活动监听:覆盖核心交互场景,保证只要用户有操作就重置无操作计时。
  • 定时检查:避免实时监听带来的性能消耗,同时确保超时状态能被及时检测。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 22:03:34