import jwt, { SignOptions } from 'jsonwebtoken'; import debug from 'debug'; const logger = { info: debug('auth-core:jwt:info'), error: debug('auth-core:jwt:error') }; const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key'; const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '7d'; export interface JWTPayload { id: number; username: string; roles?: string[]; openid?: string; } export class JWTService { /** * 生成 JWT token * @param payload JWT payload 数据 * @param expiresIn 过期时间 * @returns JWT token */ static generateToken(payload: JWTPayload, expiresIn?: string): string { if (!payload.id || !payload.username) { throw new Error('用户ID和用户名不能为空'); } try { const options: SignOptions = { expiresIn: expiresIn || JWT_EXPIRES_IN as SignOptions['expiresIn'] }; return jwt.sign(payload, JWT_SECRET, options); } catch (error) { logger.error('生成JWT token失败:', error); throw new Error('生成token失败'); } } /** * 验证 JWT token * @param token JWT token * @returns 验证后的 payload */ static verifyToken(token: string): JWTPayload { try { return jwt.verify(token, JWT_SECRET) as JWTPayload; } catch (error) { logger.error('验证JWT token失败:', error); throw new Error('无效的token'); } } /** * 解码 JWT token(不验证签名) * @param token JWT token * @returns 解码后的 payload */ static decodeToken(token: string): JWTPayload | null { try { return jwt.decode(token) as JWTPayload; } catch (error) { logger.error('解码JWT token失败:', error); return null; } } /** * 获取 token 的剩余有效期(秒) * @param token JWT token * @returns 剩余有效期(秒),如果 token 无效则返回 0 */ static getTokenRemainingTime(token: string): number { try { const decoded = jwt.verify(token, JWT_SECRET) as JWTPayload & { exp: number }; const currentTime = Math.floor(Date.now() / 1000); return Math.max(0, decoded.exp - currentTime); } catch (error) { return 0; } } }