// Package jwtx 轻量 HS256 JWT(标准库实现,零外部依赖)。 // // 密钥显式传入(不落包内全局状态),由调用方从配置注入。 // Claims 载荷为登录令牌通用三字段(uid/role/exp),业务扩展字段请自行加签发方案。 package jwtx import ( "crypto/hmac" "crypto/sha256" "encoding/base64" "encoding/json" "errors" "strings" "time" ) var ( // ErrInvalidToken token 无效。 ErrInvalidToken = errors.New("无效的 token") // ErrExpired token 已过期。 ErrExpired = errors.New("token 已过期") ) // Claims JWT 载荷(登录令牌通用字段)。 type Claims struct { UserID int64 `json:"uid"` Role string `json:"role"` // admin / user / console ... Exp int64 `json:"exp"` // 过期时间(Unix 秒) } // Sign 生成 HS256 token。 func Sign(secret string, claims Claims) (string, error) { header := base64.RawURLEncoding.EncodeToString([]byte(`{"alg":"HS256","typ":"JWT"}`)) payload, err := json.Marshal(claims) if err != nil { return "", err } body := base64.RawURLEncoding.EncodeToString(payload) signingInput := header + "." + body sig := sign(signingInput, secret) return signingInput + "." + sig, nil } // Parse 校验并解析 token(签名不符返回 ErrInvalidToken,过期返回 ErrExpired)。 func Parse(secret, token string) (*Claims, error) { parts := strings.Split(token, ".") if len(parts) != 3 { return nil, ErrInvalidToken } signingInput := parts[0] + "." + parts[1] if !hmac.Equal([]byte(sign(signingInput, secret)), []byte(parts[2])) { return nil, ErrInvalidToken } payload, err := base64.RawURLEncoding.DecodeString(parts[1]) if err != nil { return nil, ErrInvalidToken } var claims Claims if err = json.Unmarshal(payload, &claims); err != nil { return nil, ErrInvalidToken } if claims.Exp > 0 && time.Now().Unix() > claims.Exp { return nil, ErrExpired } return &claims, nil } func sign(input, secret string) string { mac := hmac.New(sha256.New, []byte(secret)) mac.Write([]byte(input)) return base64.RawURLEncoding.EncodeToString(mac.Sum(nil)) }