使用golang-jwt生成JWT后自定义Claims丢失问题排查
问题原因与解决方法
核心问题
你的自定义Claims结构体中userid是小写开头的字段,在Go语言里小写字段属于私有字段,golang-jwt库依赖反射机制序列化/反序列化Claims,而反射无法访问私有字段,导致userid根本没被写入JWT的payload中。解析时自然只能拿到int类型的默认值0。
解决步骤
- 将自定义Claims中的字段改为大写开头(公开字段),让反射机制可以访问
- 可选但推荐:添加
json标签,指定JWT payload中对应的字段名(符合常规命名习惯)
修改后的代码示例
package main import ( "fmt" "time" "github.com/golang-jwt/jwt/v4" ) // 修改字段为公开字段,添加json标签指定payload中的键名 type MyCustomClaims struct { UserID int `json:"userid"` jwt.RegisteredClaims } func (app *Config) generateJWT(userid int) { // 生成JWT jt := jwt.NewWithClaims(jwt.SigningMethodHS256, MyCustomClaims{ UserID: userid, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(3 * time.Hour)), IssuedAt: jwt.NewNumericDate(time.Now()), }, }) fmt.Println("What was put", jt.Claims.(MyCustomClaims).UserID) // 不要忽略签名错误 token, err := jt.SignedString(app.secret) if err != nil { fmt.Println("签名失败:", err) return } // 解析并验证JWT parsedToken, err := jwt.ParseWithClaims(token, &MyCustomClaims{}, func(t *jwt.Token) (interface{}, error) { return app.secret, nil }) if err != nil { fmt.Println("解析失败:", err) return } // 安全转换Claims类型并验证token有效性 if claims, ok := parsedToken.Claims.(*MyCustomClaims); ok && parsedToken.Valid { fmt.Println("What was parsed", claims.UserID) } else { fmt.Println("无效Token或Claims类型转换失败") } }
额外注意事项
- 永远不要忽略
SignedString和ParseWithClaims返回的错误,否则会隐藏签名失败、Token无效等潜在问题 - Go的结构体字段可见性严格区分大小写,只有大写开头的字段能被包外的代码(包括反射机制)访问
内容的提问来源于stack exchange,提问作者Sushant
相关产品推荐
相关产品推荐

