Go实现JWT令牌生成和解析
Reverse Lv4

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package utils

import (
"commander-server-t260220/internal/types"
"errors"
"time"

"github.com/golang-jwt/jwt/v5"
)

// 1. 定义 Claims 结构体,必须包含 jwt.RegisteredClaims
type CustomClaims struct {
UserID uint `json:"user_id"`
jwt.RegisteredClaims
}

type JwtUtils struct {
secret []byte // 内部统一使用 []byte 提高效率
}

func NewJwtUtils(config *types.ServerConfig) *JwtUtils {
return &JwtUtils{secret: []byte(config.Server.JwtSecret)}
}

// GenerateToken 生成 JWT 令牌
func (j *JwtUtils) GenerateToken(userID uint) (string, error) {
claims := CustomClaims{
UserID: userID,
RegisteredClaims: jwt.RegisteredClaims{
// 建议设置签发人(Issuer)和过期时间
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
NotBefore: jwt.NewNumericDate(time.Now()),
},
}

// 使用 HS256 签名算法
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(j.secret)
}

// ParseToken 解析并验证 JWT 令牌
func (j *JwtUtils) ParseToken(tokenString string) (uint, error) {
// 解析令牌
token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(t *jwt.Token) (interface{}, error) {
// 验证签名算法是否为 HS256,防止算法降级攻击
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, errors.New("unexpected signing method")
}
return j.secret, nil
})

if err != nil {
return 0, err
}

// 校验 claims 是否有效并提取数据
if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
return claims.UserID, nil
}

return 0, errors.New("invalid token")
}

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"fmt"
)

func main() {

// 初始化 JWT 工具类
jwtUtils := utils.NewJwtUtils(config)

// 假设 userID 为 1
token, err := jwtUtils.GenerateToken(1)
if err != nil {
log.Fatalf("生成 JWT 令牌失败: %v", err)
}
fmt.Println(token)

// 解析 JWT 令牌
userID, err := jwtUtils.ParseToken(token)
if err != nil {
log.Fatalf("解析 JWT 令牌失败: %v", err)
}
fmt.Println(userID)

}