92 lines
2.2 KiB
Go
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
|
|
}
|