73 lines
2.1 KiB
Go
73 lines
2.1 KiB
Go
// 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))
|
|
}
|