jwt.service.ts 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import jwt, { SignOptions } from 'jsonwebtoken';
  2. import debug from 'debug';
  3. const logger = {
  4. info: debug('auth-core:jwt:info'),
  5. error: debug('auth-core:jwt:error')
  6. };
  7. const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key';
  8. const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '7d';
  9. export interface JWTPayload {
  10. id: number;
  11. username: string;
  12. roles?: string[];
  13. openid?: string;
  14. }
  15. export class JWTService {
  16. /**
  17. * 生成 JWT token
  18. * @param payload JWT payload 数据
  19. * @param expiresIn 过期时间
  20. * @returns JWT token
  21. */
  22. static generateToken(payload: JWTPayload, expiresIn?: string): string {
  23. if (!payload.id || !payload.username) {
  24. throw new Error('用户ID和用户名不能为空');
  25. }
  26. try {
  27. const options: SignOptions = {
  28. expiresIn: expiresIn || JWT_EXPIRES_IN as SignOptions['expiresIn']
  29. };
  30. return jwt.sign(payload, JWT_SECRET, options);
  31. } catch (error) {
  32. logger.error('生成JWT token失败:', error);
  33. throw new Error('生成token失败');
  34. }
  35. }
  36. /**
  37. * 验证 JWT token
  38. * @param token JWT token
  39. * @returns 验证后的 payload
  40. */
  41. static verifyToken(token: string): JWTPayload {
  42. try {
  43. return jwt.verify(token, JWT_SECRET) as JWTPayload;
  44. } catch (error) {
  45. logger.error('验证JWT token失败:', error);
  46. throw new Error('无效的token');
  47. }
  48. }
  49. /**
  50. * 解码 JWT token(不验证签名)
  51. * @param token JWT token
  52. * @returns 解码后的 payload
  53. */
  54. static decodeToken(token: string): JWTPayload | null {
  55. try {
  56. return jwt.decode(token) as JWTPayload;
  57. } catch (error) {
  58. logger.error('解码JWT token失败:', error);
  59. return null;
  60. }
  61. }
  62. /**
  63. * 获取 token 的剩余有效期(秒)
  64. * @param token JWT token
  65. * @returns 剩余有效期(秒),如果 token 无效则返回 0
  66. */
  67. static getTokenRemainingTime(token: string): number {
  68. try {
  69. const decoded = jwt.verify(token, JWT_SECRET) as JWTPayload & { exp: number };
  70. const currentTime = Math.floor(Date.now() / 1000);
  71. return Math.max(0, decoded.exp - currentTime);
  72. } catch (error) {
  73. return 0;
  74. }
  75. }
  76. }