jwt.go 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package auth
  2. import (
  3. "errors"
  4. "time"
  5. "perms-system-server/internal/consts"
  6. "perms-system-server/internal/middleware"
  7. "github.com/golang-jwt/jwt/v4"
  8. )
  9. var ErrTokenTypeMismatch = errors.New("token type mismatch")
  10. type RefreshClaims struct {
  11. TokenType string `json:"tokenType"`
  12. UserId int64 `json:"userId"`
  13. ProductCode string `json:"productCode"`
  14. TokenVersion int64 `json:"tokenVersion"`
  15. jwt.RegisteredClaims
  16. }
  17. func GenerateAccessToken(secret string, expireSeconds int64, userId int64, username, productCode, memberType string, tokenVersion int64) (string, error) {
  18. now := time.Now()
  19. claims := middleware.Claims{
  20. TokenType: consts.TokenTypeAccess,
  21. UserId: userId,
  22. Username: username,
  23. ProductCode: productCode,
  24. MemberType: memberType,
  25. TokenVersion: tokenVersion,
  26. RegisteredClaims: jwt.RegisteredClaims{
  27. ExpiresAt: jwt.NewNumericDate(now.Add(time.Duration(expireSeconds) * time.Second)),
  28. IssuedAt: jwt.NewNumericDate(now),
  29. },
  30. }
  31. token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  32. return token.SignedString([]byte(secret))
  33. }
  34. func GenerateRefreshToken(secret string, expireSeconds int64, userId int64, productCode string, tokenVersion int64) (string, error) {
  35. now := time.Now()
  36. claims := RefreshClaims{
  37. TokenType: consts.TokenTypeRefresh,
  38. UserId: userId,
  39. ProductCode: productCode,
  40. TokenVersion: tokenVersion,
  41. RegisteredClaims: jwt.RegisteredClaims{
  42. ExpiresAt: jwt.NewNumericDate(now.Add(time.Duration(expireSeconds) * time.Second)),
  43. IssuedAt: jwt.NewNumericDate(now),
  44. },
  45. }
  46. token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  47. return token.SignedString([]byte(secret))
  48. }
  49. // GenerateRefreshTokenWithExpiry 签发 refreshToken,使用绝对过期时间(用于 token 轮转场景)。
  50. func GenerateRefreshTokenWithExpiry(secret string, expiresAt time.Time, userId int64, productCode string, tokenVersion int64) (string, error) {
  51. now := time.Now()
  52. if !expiresAt.After(now) {
  53. return "", errors.New("refresh token has expired")
  54. }
  55. claims := RefreshClaims{
  56. TokenType: consts.TokenTypeRefresh,
  57. UserId: userId,
  58. ProductCode: productCode,
  59. TokenVersion: tokenVersion,
  60. RegisteredClaims: jwt.RegisteredClaims{
  61. ExpiresAt: jwt.NewNumericDate(expiresAt),
  62. IssuedAt: jwt.NewNumericDate(now),
  63. },
  64. }
  65. token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  66. return token.SignedString([]byte(secret))
  67. }
  68. func ParseRefreshToken(tokenStr, secret string) (*RefreshClaims, error) {
  69. token, err := jwt.ParseWithClaims(tokenStr, &RefreshClaims{}, func(token *jwt.Token) (interface{}, error) {
  70. return []byte(secret), nil
  71. })
  72. if err != nil {
  73. return nil, err
  74. }
  75. claims, ok := token.Claims.(*RefreshClaims)
  76. if !ok || !token.Valid {
  77. return nil, jwt.ErrSignatureInvalid
  78. }
  79. if claims.TokenType != consts.TokenTypeRefresh {
  80. return nil, ErrTokenTypeMismatch
  81. }
  82. return claims, nil
  83. }