Files
zonat/internal/node/jwt.go
T

61 lines
1.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// jwt.go agent 登录令牌的 JWT 校验与签发(HS256)。
// 正式部署由签发方(如 cloud)生成 token 下发给各隧道;节点只做校验。
// SignToken 供 cmd/node -print-token(运维手工签发)与测试使用。
package node
import (
"errors"
"fmt"
"time"
"github.com/golang-jwt/jwt/v5"
)
// verifyToken 校验 agent 登录 JWT:
// - HS256/384/512 签名(显式白名单,拒绝 none 与其它算法)
// - 必须带 exp 且未过期
// - 若带 agentId 或 sub claim,则必须与登录 AgentId 一致(防跨 agent 冒用)
func verifyToken(token, secret, agentId string) error {
if secret == "" {
return errors.New("节点未配置JWT密钥")
}
parsed, err := jwt.Parse(token, func(t *jwt.Token) (any, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("签名算法不允许:%v", t.Header["alg"])
}
return []byte(secret), nil
}, jwt.WithValidMethods([]string{
jwt.SigningMethodHS256.Alg(),
jwt.SigningMethodHS384.Alg(),
jwt.SigningMethodHS512.Alg(),
}), jwt.WithExpirationRequired())
if err != nil {
return err
}
claims, ok := parsed.Claims.(jwt.MapClaims)
if !ok {
return errors.New("claims类型错误")
}
for _, k := range []string{"agentId", "sub"} {
if v, ok := claims[k].(string); ok && v != "" && v != agentId {
return fmt.Errorf("token %s 与登录agentId不一致", k)
}
}
return nil
}
// SignToken 用节点密钥签发一张 agent 登录 JWT。
// ttl<=0 会得到立即过期的 token(仅测试构造过期样例时有意义)。
func SignToken(secret, agentId string, ttl time.Duration) (string, error) {
if secret == "" {
return "", errors.New("未配置JWT密钥")
}
now := time.Now()
claims := jwt.MapClaims{
"agentId": agentId,
"iat": now.Unix(),
"exp": now.Add(ttl).Unix(),
}
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(secret))
}