Files
ppgo_job/libs/jwt.go
T
2026-07-10 11:28:16 +08:00

92 lines
2.2 KiB
Go

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
}