Golang JWT 生成与解析
前言
没有前言。
生成Payload
我们可以直接使用golang-jwt
中的RegisteredClaims
结构:
jwt.RegisteredClaims{
// 发行人主题
Issuer: "",
// 被签发者主题
Subject: "",
// 用户标识符
Audience: nil,
// 过期时间
ExpiresAt: nil,
// 不早于
NotBefore: nil,
// 签发时间
IssuedAt: nil,
// JWT的唯一标识符
ID: "",
}
此部分参见:https://datatracker.ietf.org/doc/html/rfc7519#section-4.1
或者我们可以自定义一个结构体,只需要引用RegisteredClaims
就行:
// 嵌套结构
type CustomInfo struct {
Name string `json:"name"`
}
// 自定义 payload
type CustomTokenBody struct {
*jwt.RegisteredClaims
User CustomInfo `json:"user"`
Role string
}
生成JWT
选择签署算法:
// HMAC_HS256_HS384_HS512
// RSA_RS256_RS384_RS512
// ECDSA_ES256_ES384_ES512
// EdDSA_Ed25519
signingMethodECSDA := jwt.GetSigningMethod("ES256")
新建JWT
并签署Payload
:
token := jwt.New(signingMethodECSDA)
// payload
token.Claims = &CustomTokenBody{
&jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * 10)),
},
CustomInfo{
Name: "yeziruo",
},
"yeziruo",
}
// 使用私钥签署
// key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
signedString, err := token.SignedString(key)
if err != nil {
panic(err)
}
fmt.println(signedString)
最后生成:
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NjYxNTk2NjMsInVzZXIiOnsibmFtZSI6InllemlydW8ifSwiUm9sZSI6InllemlydW8ifQ.mCatXHq0ooh49Eusr2aWLJKwwy6K_zogDBVCTc3eBzY_ygePVnFL78QpzkGeuCCyhtjdobuKGx0VxBs6PlYrQA
//payload:{"exp":1666159663,"user":{"name":"yeziruo"},"Role":"yeziruo"}
解析JWT
共有三种解析方法:
// 解析并验证
jwt.Parse
// 仅解析
jwt.ParseUnverified
// 解析并验证
jwt.ParseWithClaims
Parse
和ParseWithClaims
有一定区别:
// 解析JWT
parse, err := jwt.Parse(signedString, func(token *jwt.Token) (interface{}, error) {
// 如果你有多个私钥用于签名,那么可以在此通过 kid 来选择相应的密钥
// 这里获取的 token.Claims 是一个 map
// 返回公钥
return key.Public(), nil
})
parse, err = jwt.ParseWithClaims(signedString, &CustomTokenBody{}, func(token *jwt.Token) (interface{}, error) {
// 这里获取的 token.Claims 会被填充到指定的结构体
return key.Public(), nil
})
// err 可以返回验证失败原因
// fmt.println(err)
fmt.Println(parse.Valid)
将其作为Gin
中间件
func JWTAuth(priKey *ecdsa.PrivateKey) gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
parse, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
return priKey.Public(), nil
})
if err != nil || !parse.Valid {
msg := "token verification failed"
if err != nil {
msg = err.Error()
}
c.JSON(http.StatusUnauthorized, gin.H{
"code": http.StatusUnauthorized,
"message": msg,
})
c.Abort()
} else {
c.Set("jwt", parse)
c.Next()
}
}
}
参见
https://datatracker.ietf.org/doc/html/rfc7519
https://pkg.go.dev/github.com/golang-jwt/jwt