first commit
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
// Package token 提供极简 HS256 JWT 生成与校验(仅依赖标准库)。
|
||||
// 后台管理用于登录态签发与中间件校验;小程序登录态请见各小程序 service。
|
||||
package token
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var b64 = base64.RawURLEncoding
|
||||
|
||||
// Claims 是后台 JWT 的载荷。
|
||||
type Claims struct {
|
||||
AdminID string `json:"admin_id"`
|
||||
Exp int64 `json:"exp"`
|
||||
}
|
||||
|
||||
const header = `{"alg":"HS256","typ":"JWT"}`
|
||||
|
||||
// Generate 签发一个 HS256 token。
|
||||
func Generate(secret, adminID string, ttl time.Duration) (string, error) {
|
||||
payload, err := json.Marshal(Claims{AdminID: adminID, Exp: time.Now().Add(ttl).Unix()})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
signingInput := b64.EncodeToString([]byte(header)) + "." + b64.EncodeToString(payload)
|
||||
return signingInput + "." + sign(secret, signingInput), nil
|
||||
}
|
||||
|
||||
// Parse 校验 token 签名与有效期,返回 Claims。
|
||||
func Parse(secret, tokenStr string) (*Claims, error) {
|
||||
parts := strings.Split(tokenStr, ".")
|
||||
if len(parts) != 3 {
|
||||
return nil, errors.New("invalid token format")
|
||||
}
|
||||
expected := sign(secret, parts[0]+"."+parts[1])
|
||||
if !hmac.Equal([]byte(expected), []byte(parts[2])) {
|
||||
return nil, errors.New("bad signature")
|
||||
}
|
||||
raw, err := b64.DecodeString(parts[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var claims Claims
|
||||
if err := json.Unmarshal(raw, &claims); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if claims.Exp < time.Now().Unix() {
|
||||
return nil, errors.New("token expired")
|
||||
}
|
||||
return &claims, nil
|
||||
}
|
||||
|
||||
func sign(secret, input string) string {
|
||||
mac := hmac.New(sha256.New, []byte(secret))
|
||||
mac.Write([]byte(input))
|
||||
return b64.EncodeToString(mac.Sum(nil))
|
||||
}
|
||||
Reference in New Issue
Block a user