在现代 web 应用程序中,JWT(JSON Web Token)是一种非常流行的用户身份验证机制。由于其无状态和自包含的特性,JWT 在实现分布式系统时显得尤为重要。然而,JWT 的有效期限制也给开发者带来了挑战。为了解决这一问题,我们可以采用 JWT 自动续期的策略来提升用户体验。
什么是 JWT?
JWT 是一种开放标准,用于在各方之间安全地传递信息。JWT 由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。这三部分使用点(.)连接成一个字符串。
头部示例
{
"alg": "HS256",
"typ": "JWT"
}
载荷示例
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"exp": 1516243022
}
签名生成
签名是利用头部和载荷通过指定算法加密生成的。在实际开发中,JWT 会指定一个过期时间(exp
),超出该时间后,用户需要重新登录才能获取新的 JWT。
JWT 自动续期的实现
为了避免用户频繁登录,我们可以在 JWT 的有效期快到时自动续期。这里我们将通过前端和后端的协作来实现自动续期。
前端实现
前端使用 JavaScript 进行 JWT 自动续期的重要步骤包括:
- 监听用户操作以检测 JWT 的过期时间。
- 当检测到 JWT 快要过期(比如小于 5 分钟)时,发起请求获取新的 JWT。
function getJwt() {
return localStorage.getItem('jwt'); // 从 localStorage 获取 JWT
}
function checkJwtExpiration() {
const jwt = getJwt();
if (!jwt) return;
const payload = JSON.parse(atob(jwt.split('.')[1]));
const exp = payload.exp * 1000; // 转换为毫秒
const currentTime = Date.now();
// 如果 JWT 过期时间小于当前时间加上 5 分钟,则自动续期
if (exp < currentTime + 5 * 60 * 1000) {
renewJwt(jwt);
}
}
function renewJwt(oldJwt) {
fetch('/api/renew', {
method: 'POST',
headers: {
'Authorization': `Bearer ${oldJwt}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.newJwt) {
localStorage.setItem('jwt', data.newJwt); // 更新 JWT
}
})
.catch(error => {
console.error('Renew JWT Failed:', error);
});
}
// 监听用户的活动
setInterval(checkJwtExpiration, 30000); // 每 30 秒检查一次
后端实现
后端需要提供一个新的 API 接口来处理 JWT 的续期请求。下面是一个基于 Node.js 的示例:
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
app.use(express.json());
const SECRET_KEY = 'your_secret_key'; // 密钥
const TOKEN_EXPIRY = '1h'; // 原 token 有效时间
app.post('/api/renew', (req, res) => {
const token = req.headers['authorization'].split(' ')[1];
jwt.verify(token, SECRET_KEY, (err, decoded) => {
if (err) {
return res.status(401).json({ message: 'Token is invalid' });
}
// 生成新的 token
const newToken = jwt.sign({ sub: decoded.sub }, SECRET_KEY, { expiresIn: TOKEN_EXPIRY });
res.json({ newJwt: newToken });
});
});
// 启动服务
app.listen(3000, () => {
console.log('Server started on http://localhost:3000');
});
总结
通过上述方法,我们实现了 JWT 的自动续期机制,提升了用户体验。前端通过监听 JWT 的过期时间,适时请求续期;后端提供了新的联机 API 来签发新的 JWT。这种方法有效地减少了用户频繁登录的麻烦,使应用程序更加友好。