JWT 设置24小时有效期及前端过期判断
1. 后端设置JWT 24小时有效期
在后端生成JWT时,可以设置exp
(expiration time)声明来指定令牌的过期时间(24小时后过期):
// Node.js 示例 (使用jsonwebtoken库)
const jwt = require('jsonwebtoken');
const secret = 'your-secret-key';
function generateToken(user) {
return jwt.sign({
userId: user.id,
// 设置24小时后过期 (以秒为单位)
exp: Math.floor(Date.now() / 1000) + (24 * 60 * 60),
// 也可以使用库的默认选项
// 例如: expiresIn: '24h'
}, secret);
}
2. 前端判断JWT是否过期
前端可以通过以下方式判断JWT是否过期:
方法1:解码JWT检查exp字段
function isTokenExpired(token) {
try {
// 解码token (不需要验证签名)
const decoded = JSON.parse(atob(token.split('.')[1]));
// 检查过期时间 (exp是以秒为单位的时间戳)
return decoded.exp * 1000 < Date.now();
} catch (e) {
// 如果token格式无效,视为已过期
return true;
}
}
// 使用示例
const token = localStorage.getItem('jwtToken');
if (isTokenExpired(token)) {
// token已过期,执行重新登录等操作
console.log('Token已过期');
logout();
} else {
// token仍有效
console.log('Token有效');
}
方法2:使用 jwt-decode 库
安装库:
npm install jwt-decode
# 或
yarn add jwt-decode
使用示例:
import jwtDecode from 'jwt-decode';
function checkTokenExpiry() {
const token = localStorage.getItem('jwtToken');
if (!token) return true; // 没有token视为过期
try {
const { exp } = jwtDecode(token);
return exp * 1000 < Date.now();
} catch (e) {
return true; // 解码失败视为过期
}
}
// 使用示例
if (checkTokenExpiry()) {
// 执行token刷新或重新登录
refreshTokenOrLogin();
}
3. 完整的前端Token管理方案
class AuthService {
constructor() {
this.tokenKey = 'jwtToken';
this.refreshTokenKey = 'refreshToken';
}
// 保存Token
setAuthTokens({ token, refreshToken }) {
localStorage.setItem(this.tokenKey, token);
if (refreshToken) {
localStorage.setItem(this.refreshTokenKey, refreshToken);
}
}
// 获取Token
getToken() {
return localStorage.getItem(this.tokenKey);
}
// 检查Token是否有效
isTokenValid() {
const token = this.getToken();
if (!token) return false;
try {
const { exp } = jwtDecode(token);
return exp * 1000 > Date.now();
} catch {
return false;
}
}
// 刷新Token
async refreshToken() {
const refreshToken = localStorage.getItem(this.refreshTokenKey);
if (!refreshToken) throw new Error('No refresh token available');
try {
const response = await fetch('/api/auth/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ refreshToken }),
});
if (!response.ok) throw new Error('Refresh failed');
const { token, refreshToken: newRefreshToken } = await response.json();
this.setAuthTokens({ token, refreshToken: newRefreshToken });
return token;
} catch (error) {
this.clearTokens();
throw error;
}
}
// 清除Token
clearTokens() {
localStorage.removeItem(this.tokenKey);
localStorage.removeItem(this.refreshTokenKey);
}
// 自动刷新Token的请求拦截器
setupInterceptor(axiosInstance) {
axiosInstance.interceptors.request.use(async (config) => {
if (this.isTokenValid()) {
config.headers.Authorization = `Bearer ${this.getToken()}`;
return config;
}
try {
const newToken = await this.refreshToken();
config.headers.Authorization = `Bearer ${newToken}`;
return config;
} catch {
// 刷新失败,跳转到登录页
window.location.href = '/login';
return Promise.reject(new Error('Session expired'));
}
});
}
}
// 使用示例
const authService = new AuthService();
authService.setupInterceptor(axios); // 设置axios拦截器
4. 最佳实践建议
- 双重检查:即使前端检查token未过期,后端也必须验证,因为客户端时间可能被篡改
- 自动刷新:实现token自动刷新机制,在token快过期时自动获取新token
- 安全存储:考虑使用HttpOnly cookies存储token,增加安全性
- 过期处理:提供良好的用户体验,token过期时提示用户或自动刷新
- 时间同步:确保客户端和服务器时间同步,避免因时间差导致的判断错误
5. 定时检查Token过期
可以在应用初始化时设置定时器,定期检查token状态:
function setupTokenChecker(authService) {
// 每分钟检查一次
setInterval(() => {
if (!authService.isTokenValid()) {
console.log('Token已过期或即将过期');
// 执行刷新或登出操作
}
}, 60 * 1000);
}