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

调用cognitoUser.refreshSession刷新JWT时反复跳转登录页

问题根因

你的代码存在3个致命逻辑错误,直接导致令牌刷新失效、页面频繁跳转回登录页:

  • refreshToken是async异步函数,拦截器中直接执行const idToken = refreshToken()拿到的是Pending状态的Promise对象,不是实际的JWT字符串,请求头携带的Authorization值完全无效
  • cognitoUser.refreshSession是回调风格的API,你在回调函数内部写return,返回值只会留在回调作用域内,根本无法作为refreshToken函数的返回值传递到外层调用处
  • 每次发起请求都强制刷新令牌属于错误实现:高并发场景下会同时触发多笔刷新请求,Cognito会判定旧刷新令牌被重复使用,直接吊销当前会话将用户踢下线;且刷新成功后你没有读取回调参数返回的新会话中的令牌,反而去取Auth.user上可能还未更新的旧令牌,取值逻辑完全错误。
修复实现

先明确两个基础逻辑:

  • Amplify Auth模块本身会自动维护本地会话状态,只有当现有idToken过期/即将过期时才需要触发刷新,不需要每次请求都强制刷新
  • Axios请求拦截器本身支持返回Promise,异步取令牌的逻辑直接用async/await承接即可,不需要强行写同步赋值

修复后的完整代码如下:

import axios from 'axios';
import { Auth } from 'aws-amplify';

const httpClient = axios.create({
  baseURL: process.env.VUE_APP_API_BASE_URL
});

// 将回调风格的刷新方法包装为Promise,方便异步调用
const getValidIdToken = () => {
  return new Promise(async (resolve, reject) => {
    try {
      const cognitoUser = await Auth.currentAuthenticatedUser();
      const currentSession = await Auth.currentSession();
      // 现有会话有效直接返回现有token,无需重复刷新
      if (currentSession.isValid()) {
        return resolve(currentSession.getIdToken().getJwtToken());
      }
      // 令牌过期再走刷新逻辑
      cognitoUser.refreshSession(currentSession.getRefreshToken(), (err, newSession) => {
        if (err) {
          // 刷新失败(刷新令牌过期、用户被封禁等)直接抛出错误
          return reject(err);
        }
        // 从刷新返回的新会话中取最新idToken,不要读取旧的全局用户属性
        resolve(newSession.getIdToken().getJwtToken());
      });
    } catch (e) {
      reject(e);
    }
  });
};

httpClient.interceptors.request.use(
  async config => {
    try {
      const idToken = await getValidIdToken();
      config.headers.Authorization = `Bearer ${idToken}`;
    } catch (e) {
      console.log('令牌校验/刷新失败,需重新登录', e);
      // 此处可补充你的跳转登录页逻辑,例如 router.push('/login')
    }
    return config;
  },
  error => Promise.reject(error)
);

// 可选:增加响应拦截器兜底处理401场景
httpClient.interceptors.response.use(
  response => response,
  async error => {
    if (error.response?.status === 401) {
      // 401说明令牌彻底失效,清理本地会话后跳转登录
      await Auth.signOut();
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
)

export default httpClient;
避坑提示
  • 如果你的Cognito用户池开启了刷新令牌轮换策略,必须加刷新锁:上一笔刷新请求返回前,后续所有请求都等待同一个刷新Promise完成,否则会触发Cognito的安全防护规则,直接吊销整个用户会话
  • 不要在刷新回调里手动给Auth.user.signInUserSession赋值,refreshSession调用成功后Amplify会自动更新本地存储的会话信息,手动赋值反而可能写入异常值
  • 如果页面一加载就跳登录,优先检查本地存储是否被第三方清理、应用域名是否和Cognito配置的回调域名一致,这类场景下Auth.currentAuthenticatedUser()会直接抛出无有效会话的错误,之前的代码只打日志不处理,就会表现为无感知跳登录。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 03:57:20