151 lines
3.6 KiB
JavaScript
151 lines
3.6 KiB
JavaScript
|
|
const jwt = require('jsonwebtoken');
|
|||
|
|
const logger = require('./logger');
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* JWT 工具类
|
|||
|
|
* 提供 token 生成、验证、刷新等功能
|
|||
|
|
*/
|
|||
|
|
class JWTUtils {
|
|||
|
|
constructor() {
|
|||
|
|
this.secret = process.env.JWT_SECRET || 'your-secret-key';
|
|||
|
|
this.refreshSecret = process.env.JWT_REFRESH_SECRET || 'your-refresh-secret-key';
|
|||
|
|
// Access token 过期时间(默认 2 小时)
|
|||
|
|
this.accessTokenExpiry = process.env.JWT_ACCESS_EXPIRY || '24h';
|
|||
|
|
// Refresh token 过期时间(默认 7 天)
|
|||
|
|
this.refreshTokenExpiry = process.env.JWT_REFRESH_EXPIRY || '7d';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 生成访问令牌
|
|||
|
|
* @param {Object} payload - 用户信息载荷
|
|||
|
|
* @returns {String} access token
|
|||
|
|
*/
|
|||
|
|
generateAccessToken(payload) {
|
|||
|
|
const data = {
|
|||
|
|
userId: payload.userId,
|
|||
|
|
username: payload.username,
|
|||
|
|
corpId: payload.corpId,
|
|||
|
|
role: payload.role,
|
|||
|
|
type: 'access',
|
|||
|
|
platform: payload.platform || '',
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return jwt.sign(data, this.secret, {
|
|||
|
|
expiresIn: this.accessTokenExpiry,
|
|||
|
|
issuer: 'zyt-hlw-service'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 生成刷新令牌
|
|||
|
|
* @param {Object} payload - 用户信息载荷
|
|||
|
|
* @returns {String} refresh token
|
|||
|
|
*/
|
|||
|
|
generateRefreshToken(payload) {
|
|||
|
|
const data = {
|
|||
|
|
userId: payload.userId,
|
|||
|
|
username: payload.username,
|
|||
|
|
type: 'refresh'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return jwt.sign(data, this.refreshSecret, {
|
|||
|
|
expiresIn: this.refreshTokenExpiry,
|
|||
|
|
issuer: 'zyt-hlw-service'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 生成访问令牌和刷新令牌
|
|||
|
|
* @param {Object} payload - 用户信息载荷
|
|||
|
|
* @returns {Object} { accessToken, refreshToken }
|
|||
|
|
*/
|
|||
|
|
generateTokens(payload) {
|
|||
|
|
const accessToken = this.generateAccessToken(payload);
|
|||
|
|
const refreshToken = this.generateRefreshToken(payload);
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
accessToken,
|
|||
|
|
refreshToken,
|
|||
|
|
expiresIn: this.parseExpiry(this.accessTokenExpiry)
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 验证访问令牌
|
|||
|
|
* @param {String} token - 访问令牌
|
|||
|
|
* @returns {Object} 解码后的载荷
|
|||
|
|
*/
|
|||
|
|
verifyAccessToken(token) {
|
|||
|
|
return jwt.verify(token, this.secret);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 验证刷新令牌
|
|||
|
|
* @param {String} token - 刷新令牌
|
|||
|
|
* @returns {Object} 解码后的载荷
|
|||
|
|
*/
|
|||
|
|
verifyRefreshToken(token) {
|
|||
|
|
return jwt.verify(token, this.refreshSecret);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 使用刷新令牌生成新的访问令牌
|
|||
|
|
* @param {String} refreshToken - 刷新令牌
|
|||
|
|
* @returns {Object} { accessToken, expiresIn }
|
|||
|
|
*/
|
|||
|
|
refreshAccessToken(refreshToken) {
|
|||
|
|
const decoded = this.verifyRefreshToken(refreshToken);
|
|||
|
|
|
|||
|
|
if (decoded.type !== 'refresh') {
|
|||
|
|
throw new Error('Invalid token type');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生成新的访问令牌
|
|||
|
|
const accessToken = this.generateAccessToken({
|
|||
|
|
userId: decoded.userId,
|
|||
|
|
username: decoded.username
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
accessToken,
|
|||
|
|
expiresIn: this.parseExpiry(this.accessTokenExpiry)
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 解析过期时间字符串为秒数
|
|||
|
|
* @param {String} expiry - 过期时间字符串(如 '2h', '7d')
|
|||
|
|
* @returns {Number} 秒数
|
|||
|
|
*/
|
|||
|
|
parseExpiry(expiry) {
|
|||
|
|
const match = expiry.match(/^(\d+)([smhd])$/);
|
|||
|
|
if (!match) return 7200; // 默认 2 小时
|
|||
|
|
|
|||
|
|
const value = parseInt(match[1]);
|
|||
|
|
const unit = match[2];
|
|||
|
|
|
|||
|
|
const multipliers = {
|
|||
|
|
's': 1,
|
|||
|
|
'm': 60,
|
|||
|
|
'h': 3600,
|
|||
|
|
'd': 86400
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return value * (multipliers[unit] || 3600);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 解码 token(不验证签名)
|
|||
|
|
* @param {String} token
|
|||
|
|
* @returns {Object} 解码后的载荷
|
|||
|
|
*/
|
|||
|
|
decode(token) {
|
|||
|
|
return jwt.decode(token);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 导出单例
|
|||
|
|
module.exports = new JWTUtils();
|
|||
|
|
|
|||
|
|
|