基于AWS Cognito SDK的React应用:如何用刷新后的JWT令牌调用API?
实现AWS Cognito刷新JWT令牌并调用API的React方案
看了你当前的代码,你现在是在componentWillMount里做会话检查,但要实现自动刷新JWT令牌并安全调用API的话,咱们可以基于AWS Cognito的SDK(推荐用Amplify封装的版本,更省心)来调整逻辑,同时把一些不安全的生命周期方法替换掉。
核心思路
AWS Cognito的JS SDK其实自带了令牌刷新的能力,我们只需要利用Auth.currentSession()方法——它会自动检查访问令牌是否过期,如果过期且刷新令牌有效,就会自动去获取新的访问令牌和ID令牌。我们要做的就是在调用API前确保拿到的是有效令牌,然后把它放到请求头里。
具体实现步骤(类组件版本)
首先,确保你已经安装并配置了AWS Amplify(如果还没的话,先跑npm install aws-amplify并配置你的Cognito信息)。
- 封装获取有效令牌的函数
在你的组件里添加一个异步函数,用来获取或刷新令牌:
import { Auth } from 'aws-amplify'; class YourComponent extends React.Component { // 获取有效访问令牌,自动处理刷新 async getValidAccessToken() { try { const session = await Auth.currentSession(); const accessToken = session.getAccessToken(); // 可以提前检查令牌是否即将过期(比如提前5分钟),主动刷新 const expiresAtMs = accessToken.getExpiration() * 1000; // 转成毫秒 if (Date.now() > expiresAtMs - 300000) { // 强制刷新会话 const refreshedSession = await Auth.refreshSession(session.getRefreshToken()); return refreshedSession.getAccessToken().getJwtToken(); } // 令牌还没过期,直接返回 return accessToken.getJwtToken(); } catch (error) { // 刷新失败(比如刷新令牌也过期了),跳转到登录页 this.props.history.push('/auth/login'); throw error; // 抛出错误让上层处理 } }
- 替换生命周期方法
React官方已经标记componentWillMount为不安全,建议换成componentDidMount,然后在里面初始化用户信息和令牌:
componentDidMount() { if (!this.props.authenticated) { this.props.history.push('/auth/login'); return; } // 初始化用户和令牌 this.initUserAndToken(); } async initUserAndToken() { try { // 获取当前认证用户的信息 const user = await Auth.currentAuthenticatedUser(); // 同步到Redux状态 this.props.setUserToReduxState(user.attributes); // 获取有效令牌 const accessToken = await this.getValidAccessToken(); // 把令牌存到组件state,方便后续API调用 this.setState({ accessToken }, () => { // 现在可以调用你的API了 this.callYourAPI(); }); } catch (error) { console.error('初始化用户和令牌失败:', error); this.props.history.push('/auth/login'); } }
- 带令牌调用API
在你的API调用函数里,把令牌放到Authorization请求头:
async callYourAPI() { const { accessToken } = this.state; if (!accessToken) return; try { const response = await fetch('/your-api-endpoint', { method: 'GET', // 或者POST/PUT等 headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' } }); const data = await response.json(); // 处理API返回的数据 console.log('API返回数据:', data); } catch (error) { console.error('API调用失败:', error); } } }
额外优化建议
- 复用逻辑:可以把令牌刷新的逻辑封装成高阶组件(HOC)或者自定义Hook,这样多个组件都能复用,不用重复写代码。比如自定义Hook版本:
import { useState, useEffect } from 'react'; import { Auth } from 'aws-amplify'; export const useValidAccessToken = () => { const [accessToken, setAccessToken] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchToken = async () => { try { const session = await Auth.currentSession(); const accessToken = session.getAccessToken(); const expiresAtMs = accessToken.getExpiration() * 1000; if (Date.now() > expiresAtMs - 300000) { const refreshedSession = await Auth.refreshSession(session.getRefreshToken()); setAccessToken(refreshedSession.getAccessToken().getJwtToken()); } else { setAccessToken(accessToken.getJwtToken()); } } catch (err) { setError(err); } finally { setLoading(false); } }; fetchToken(); }, []); return { accessToken, loading, error }; };
在函数组件里直接用这个Hook就能拿到有效令牌,还能处理加载和错误状态。
- 自动拦截API请求:可以用Axios的拦截器,在所有API请求前自动获取有效令牌并添加到请求头,这样每个API调用不用手动加头,更方便。比如:
import axios from 'axios'; import { Auth } from 'aws-amplify'; const api = axios.create({ baseURL: '/your-api-base-url' }); // 请求拦截器 api.interceptors.request.use(async (config) => { const session = await Auth.currentSession(); const accessToken = session.getAccessToken().getJwtToken(); config.headers.Authorization = `Bearer ${accessToken}`; return config; }, (error) => { return Promise.reject(error); }); // 然后用api.get('/endpoint')调用,自动带令牌
内容的提问来源于stack exchange,提问作者dankthreads
相关产品推荐
相关产品推荐

