feat: 新增 snowid(雪花ID+GORM钩子模板,吸收go-hua); wsc新增SessionClient会话层(吸收两端internal/cloud); jwtx重写为标准三段式HS256+密钥显式传参

This commit is contained in:
w11
2026-09-19 21:12:44 +08:00
parent 9ef71f51d4
commit 83679e2080
8 changed files with 452 additions and 42 deletions
+41 -30
View File
@@ -1,4 +1,7 @@
// Package jwtx 轻量 JWT(HMAC-SHA256),无外部依赖。
// Package jwtx 轻量 HS256 JWT(标准库实现,零外部依赖)。
//
// 密钥显式传入(不落包内全局状态),由调用方从配置注入。
// Claims 载荷为登录令牌通用三字段(uid/role/exp),业务扩展字段请自行加签发方案。
package jwtx
import (
@@ -11,51 +14,59 @@ import (
"time"
)
// Claims 登录令牌载荷。
var (
// ErrInvalidToken token 无效。
ErrInvalidToken = errors.New("无效的 token")
// ErrExpired token 已过期。
ErrExpired = errors.New("token 已过期")
)
// Claims JWT 载荷(登录令牌通用字段)。
type Claims struct {
Uid int64 `json:"uid"`
Exp int64 `json:"exp"`
Msg string `json:"msg,omitempty"`
UserID int64 `json:"uid"`
Role string `json:"role"` // admin / user / console ...
Exp int64 `json:"exp"` // 过期时间(Unix 秒)
}
var secret = []byte("zo-maintain-jwt-secret-2026")
// Sign 签发 token(TTL 秒)。
func Sign(uid int64, ttlSeconds int64) (string, error) {
payload, err := json.Marshal(Claims{Uid: uid, Exp: time.Now().Add(time.Duration(ttlSeconds) * time.Second).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)
sig := sign(body)
return body + "." + sig, nil
signingInput := header + "." + body
sig := sign(signingInput, secret)
return signingInput + "." + sig, nil
}
// Parse 校验并解析 token。
func Parse(token string) (*Claims, error) {
parts := strings.SplitN(token, ".", 2)
if len(parts) != 2 {
return nil, errors.New("令牌格式错误")
// Parse 校验并解析 token(签名不符返回 ErrInvalidToken,过期返回 ErrExpired)。
func Parse(secret, token string) (*Claims, error) {
parts := strings.Split(token, ".")
if len(parts) != 3 {
return nil, ErrInvalidToken
}
if sign(parts[0]) != parts[1] {
return nil, errors.New("令牌签名校验失败")
signingInput := parts[0] + "." + parts[1]
if !hmac.Equal([]byte(sign(signingInput, secret)), []byte(parts[2])) {
return nil, ErrInvalidToken
}
payload, err := base64.RawURLEncoding.DecodeString(parts[0])
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
return nil, errors.New("令牌载荷解析失败")
return nil, ErrInvalidToken
}
var c Claims
if err = json.Unmarshal(payload, &c); err != nil {
return nil, errors.New("令牌载荷解析失败")
var claims Claims
if err = json.Unmarshal(payload, &claims); err != nil {
return nil, ErrInvalidToken
}
if c.Exp < time.Now().Unix() {
return nil, errors.New("令牌已过期")
if claims.Exp > 0 && time.Now().Unix() > claims.Exp {
return nil, ErrExpired
}
return &c, nil
return &claims, nil
}
func sign(body string) string {
mac := hmac.New(sha256.New, secret)
mac.Write([]byte(body))
func sign(input, secret string) string {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(input))
return base64.RawURLEncoding.EncodeToString(mac.Sum(nil))
}