package libs import ( "crypto/hmac" "crypto/sha256" "encoding/base64" "encoding/json" "fmt" "strings" "time" ) // JWT secret key - loaded from config var jwtSecret = []byte("ppgo_job_secret_key_2024") // SetJWTSecret 设置 JWT 密钥(从配置文件加载) func SetJWTSecret(secret string) { if secret != "" { jwtSecret = []byte(secret) } } // JWTClaims JWT 载荷 type JWTClaims struct { UserId int `json:"userId"` RealName string `json:"realName"` ExpiresAt int64 `json:"exp"` IssuedAt int64 `json:"iat"` } // GenerateJWT 生成 JWT token func GenerateJWT(userId int, realName string) (string, error) { now := time.Now() claims := JWTClaims{ UserId: userId, RealName: realName, ExpiresAt: now.Add(24 * time.Hour).Unix(), IssuedAt: now.Unix(), } // 将 claims 序列化为 JSON payload, err := json.Marshal(claims) if err != nil { return "", fmt.Errorf("marshal claims failed: %w", err) } // Base64 编码 header 和 payload header := base64.RawURLEncoding.EncodeToString([]byte(`{"alg":"HS256","typ":"JWT"}`)) b64Payload := base64.RawURLEncoding.EncodeToString(payload) // 计算签名: HMAC-SHA256(header.payload, secret) mac := hmac.New(sha256.New, jwtSecret) mac.Write([]byte(header + "." + b64Payload)) signature := base64.RawURLEncoding.EncodeToString(mac.Sum(nil)) return fmt.Sprintf("%s.%s.%s", header, b64Payload, signature), nil } // ParseJWT 解析并验证 JWT token func ParseJWT(token string) (*JWTClaims, error) { parts := strings.Split(token, ".") if len(parts) != 3 { return nil, fmt.Errorf("invalid token format") } // 验证签名 mac := hmac.New(sha256.New, jwtSecret) mac.Write([]byte(parts[0] + "." + parts[1])) expectedSig := base64.RawURLEncoding.EncodeToString(mac.Sum(nil)) if parts[2] != expectedSig { return nil, fmt.Errorf("invalid token signature") } // 解析 payload payload, err := base64.RawURLEncoding.DecodeString(parts[1]) if err != nil { return nil, fmt.Errorf("decode payload failed: %w", err) } var claims JWTClaims if err := json.Unmarshal(payload, &claims); err != nil { return nil, fmt.Errorf("unmarshal claims failed: %w", err) } // 检查过期 if time.Now().Unix() > claims.ExpiresAt { return nil, fmt.Errorf("token expired") } return &claims, nil }