刷新access token
是的,每次刷新页面或在某个特定的情况下(如访问受保护的路由)都需要检查是否存在 refresh token
,并使用它来重新生成一个新的 access token
。这通常是为了确保用户会话的安全性和连续性。
以下是一个典型的实现步骤:
- 客户端初始化: 每次页面加载时,客户端(通常是前端代码,如 React 应用)会检查是否存在
refresh token
(通常存储在 cookies 中)。 - 发送请求以刷新令牌: 如果存在
refresh token
,客户端会发送请求到服务器以刷新access token
。 - 服务器验证: 服务器接收到请求后,会验证
refresh token
的有效性。如果有效,则生成新的access token
并返回给客户端。 - 存储新令牌: 客户端收到新的
access token
后,会将其存储在合适的位置(如内存、状态管理工具中)。 - 使用新令牌: 客户端在后续的 API 请求中使用新的
access token
进行身份验证。
下面是一个基本的前端代码示例,展示如何在页面加载时检查并刷新 access token
:
前端(React 示例)
import React, { useEffect } from 'react';
import axios from 'axios';
const App = () => {
useEffect(() => {
const refreshAccessToken = async () => {
try {
const response = await axios.get('/auth/refresh', { withCredentials: true });
const newAccessToken = response.data.accessToken;
// 将新令牌存储在内存或状态管理中
// 例如:localStorage.setItem('accessToken', newAccessToken);
} catch (err) {
console.error('Failed to refresh access token', err);
// 处理错误,如重定向到登录页面
}
};
refreshAccessToken();
}, []);
return (
<div>
<h1>Welcome to the App</h1>
{/* 你的其他组件 */}
</div>
);
};
export default App;
后端(Express 示例)
你的后端代码已经很好地处理了刷新令牌的逻辑。这里只是回顾一下:
const refresh = asyncHandler(async (req, res) => {
const cookies = req.cookies;
if (!cookies?.jwt) return res.status(401).json({ message: 'Unauthorized' });
const refreshToken = cookies.jwt;
jwt.verify(
refreshToken,
process.env.REFRESH_TOKEN_SECRET,
async (err, decoded) => {
if (err) return res.status(403).json({ message: 'Forbidden' });
const foundUser = await User.findOne({ username: decoded.username }).exec();
if (!foundUser) return res.status(401).json({ message: 'Unauthorized' });
const accessToken = jwt.sign(
{
"UserInfo": {
"username": foundUser.username,
"roles": foundUser.roles
}
},
process.env.ACCESS_TOKEN_SECRET,
{ expiresIn: '15m' }
);
res.json({ accessToken });
}
);
});
总结
通过这种方式,你可以确保用户在页面刷新或重新访问时保持登录状态,而不需要每次都重新登录。这种方法有助于提高用户体验,同时保证了安全性,因为 access token
的生命周期较短,且使用 refresh token
来延续会话。
Written on July 1, 2024