jwt.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. package utils
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/beego/beego/v2/server/web"
  6. "github.com/golang-jwt/jwt/v5"
  7. )
  8. // LocalTokenClaims 本地JWT token的claims结构
  9. type LocalTokenClaims struct {
  10. UserID uint `json:"user_id"`
  11. Username string `json:"username"`
  12. Role string `json:"role"`
  13. TokenType string `json:"token_type"` // "local" 标识为本地token
  14. jwt.RegisteredClaims
  15. }
  16. // GenerateLocalToken 生成本地JWT token
  17. func GenerateLocalToken(userID uint, username string, role string) (string, error) {
  18. // 从配置读取JWT密钥
  19. jwtSecret, err := web.AppConfig.String("jwt_secret")
  20. if err != nil || jwtSecret == "" {
  21. jwtSecret = "default-secret-key-please-change-in-production" // 默认密钥
  22. }
  23. // 设置token有效期为24小时
  24. expirationTime := time.Now().Add(24 * time.Hour)
  25. // 创建claims
  26. claims := &LocalTokenClaims{
  27. UserID: userID,
  28. Username: username,
  29. Role: role,
  30. TokenType: "local",
  31. RegisteredClaims: jwt.RegisteredClaims{
  32. ExpiresAt: jwt.NewNumericDate(expirationTime),
  33. IssuedAt: jwt.NewNumericDate(time.Now()),
  34. Issuer: "shudao-local-auth",
  35. },
  36. }
  37. // 创建token
  38. token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  39. // 签名token
  40. tokenString, err := token.SignedString([]byte(jwtSecret))
  41. if err != nil {
  42. return "", fmt.Errorf("生成token失败: %v", err)
  43. }
  44. return tokenString, nil
  45. }
  46. // VerifyLocalToken 验证本地JWT token并返回claims
  47. func VerifyLocalToken(tokenString string) (*LocalTokenClaims, error) {
  48. // 从配置读取JWT密钥
  49. jwtSecret, err := web.AppConfig.String("jwt_secret")
  50. if err != nil || jwtSecret == "" {
  51. jwtSecret = "default-secret-key-please-change-in-production"
  52. }
  53. // 解析token
  54. token, err := jwt.ParseWithClaims(tokenString, &LocalTokenClaims{}, func(token *jwt.Token) (interface{}, error) {
  55. // 验证签名方法
  56. if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
  57. return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
  58. }
  59. return []byte(jwtSecret), nil
  60. })
  61. if err != nil {
  62. return nil, fmt.Errorf("解析token失败: %v", err)
  63. }
  64. // 验证token有效性
  65. if claims, ok := token.Claims.(*LocalTokenClaims); ok && token.Valid {
  66. // 检查是否为本地token
  67. if claims.TokenType != "local" {
  68. return nil, fmt.Errorf("不是本地token")
  69. }
  70. return claims, nil
  71. }
  72. return nil, fmt.Errorf("token无效")
  73. }
  74. // ConvertLocalClaimsToTokenUserInfo 将本地token claims转换为TokenUserInfo
  75. func ConvertLocalClaimsToTokenUserInfo(claims *LocalTokenClaims) *TokenUserInfo {
  76. return &TokenUserInfo{
  77. AccountID: fmt.Sprintf("local_%d", claims.UserID),
  78. ID: int64(claims.UserID),
  79. Name: claims.Username,
  80. UserCode: claims.Username,
  81. ContactNumber: "",
  82. TokenType: "local",
  83. Exp: claims.ExpiresAt.Unix(),
  84. Iat: claims.IssuedAt.Unix(),
  85. }
  86. }