调用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
相关产品推荐
相关产品推荐

