基本结构#
Hedaer 部分用于描述该 JWT 的基本信息,比如其类型(通常是 JWT)以及所使用的签名算法(如 HMAC SHA256 或 RSA)。
Payload(负载)#
Payload 部分包含所传递的声明。声明是关于实体(通常是用户)和其他数据的语句。声明可以分为三种类型:注册声明、公共声明 和 私有声明。
注册声明#
这些声明是预定义的,非必须使用的但被推荐使用。官方标准定义的注册声明有 7 个
Claim(声明) | 含义 |
---|
iss(Issuer) | 发行者,标识 JWT 的发行者。 |
sub(Subject) | 主题,标识 JWT 的主题,通常指用户的唯一标识 |
aud(Audience) | 观众,标识 JWT 的接收者 |
exp(Expiration Time) | 过期时间。标识 JWT 的过期时间,这个时间必须是将来的 |
nbf(Not Before) | 不可用时间。在此时间之前,JWT 不应被接受处理 |
iat(Issued At) | 发行时间,标识 JWT 的发行时间 |
jti(JWT ID) | JWT 的唯一标识符,用于防止 JWT 被重放(即重复使用) |
公共声明:可以由使用 JWT 的人自定义,但为了避免冲突,任何新定义的声明都应已在 IANA JSON Web Token Registry
中注册或者是一个公共名称,其中包含了碰撞防抗性名称(Collision-Resistant Name)。
私有声明:发行和使用 JWT 的双方共同商定的声明,区别于 注册声明 和 公共声明。
Signature(签名)#
为了防止数据篡改,将头部和负载的信息进行一定算法处理,加上一个密钥,最后生成签名。如果使用的是 HMAC SHA256
算法,那么签名就是将编码后的头部、编码后的负载拼接起来,通过密钥进行 HMAC SHA256 运算后的结果。
基本使用#
1
| go get -u github.com/golang-jwt/jwt/v5
|
生成Token对象#
NewWithClaims 函数#
1
2
3
4
5
6
7
| mapClaims := jwt.MapClaims{
"iss": "发行者",
"sub": "主题",
"aud": "观众",
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, mapClaims)
fmt.Println(token != nil) // true
|
New 函数#
1
2
| token := jwt.New(jwt.SigningMethodHS256)
fmt.Println(token != nil) // true
|
生成JWT字符串#
使用SignedString()
函数进行生成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| func GenerateJwt(key any, method jwt.SigningMethod, claims jwt.Claims) (string, error) {
token := jwt.NewWithClaims(method, claims)//生成Token
return token.SignedString(key)//生成JWT字符串
}
func main() {
jwtKey := make([]byte, 32) // 生成32字节(256位)的密钥
if _, err := rand.Read(jwtKey); err != nil {
panic(err)
}
jwtStr, err := GenerateJwt(jwtKey, jwt.SigningMethodHS256, jwt.MapClaims{
"iss": "发行者",
"sub": "主题",
"aud": "观众",
})
if err != nil {
panic(err)
}
fmt.Println(jwtStr)
|
解析JWT字符串#
Parse 函数#
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
| func ParseJwt(key any, jwtStr string, options ...jwt.ParserOption) (jwt.Claims, error) {
token, err := jwt.Parse(jwtStr, func (token *jwt.Token) (interface{}, error) {//解析 JWT 时,使用指定的密钥进行验证。
return key, nil
}, options...)
if err != nil {
return nil, err
}
// 校验 Claims 对象是否有效,基于 exp(过期时间),nbf(不早于),iat(签发时间)等进行判断(如果有这些声明的话)。
if !token.Valid {
return nil, errors.New("invalid token")
}
return token.Claims, nil
}
func main() {
jwtKey := make([]byte, 32) // 生成32字节(256位)的密钥
if _, err := rand.Read(jwtKey); err != nil {
panic(err)
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"iss": "发行者",
"sub": "主题",
"aud": "观众",
"exp": time.Now().Add(time.Second * 10).UnixMilli(),
})
jwtStr, err := token.SignedString(jwtKey)
if err != nil {
panic(err)
}
// 解析 jwt
claims, err := ParseJwt(jwtKey, jwtStr, jwt.WithExpirationRequired())
if err != nil {
panic(err)
}
fmt.Println(claims)
|
ParseWithClaims 函数#
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
| func ParseJwtWithClaims(key any, jwtStr string, options ...jwt.ParserOption) (jwt.Claims, error) {
mc := jwt.MapClaims{}
token, err := jwt.ParseWithClaims(jwtStr, mc, func (token *jwt.Token) (interface{}, error) {
return key, nil
}, options...)
if err != nil {
return nil, err
}
// 校验 Claims 对象是否有效,基于 exp(过期时间),nbf(不早于),iat(签发时间)等进行判断(如果有这些声明的话)。
if !token.Valid {
return nil, errors.New("invalid token")
}
return token.Claims, nil
}
func main() {
jwtKey := make([]byte, 32) // 生成32字节(256位)的密钥
if _, err := rand.Read(jwtKey); err != nil {
panic(err)
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"iss": "发行者",
"sub": "主题",
"aud": "观众",
})
jwtStr, err := token.SignedString(jwtKey)
if err != nil {
panic(err)
}
// 解析 jwt
claims, err := ParseJwtWithClaims(jwtKey, jwtStr)
if err != nil {
panic(err)
}
fmt.Println(claims)
|