hn-hlw-service/utils/jwt-utils.js
2026-07-27 11:28:33 +08:00

151 lines
3.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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();