前言

没有前言。

生成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

ParseParseWithClaims有一定区别:

// 解析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()
        }
    }
}

2219143001.png

参见

https://datatracker.ietf.org/doc/html/rfc7519
https://pkg.go.dev/github.com/golang-jwt/jwt

标签: Golang, JWT

添加新评论