Go中如何正确读取JWT自定义声明至结构体?解决字段值异常
问题:Go解析JWT时Admin字段始终为false,jwt.io验证正常
我用Go代码生成带自定义声明的JWT Token,其中Admin字段设为true,在jwt.io上能正常看到该字段值为true,但通过VerifyUserToken函数解析验证时,Admin字段始终是false。相关代码如下:
生成Token的代码
func GenerateUserToken(user model.User) (string, error) { token := jwt.New(jwt.SigningMethodHS256) claims := token.Claims.(jwt.MapClaims) claims["iss"] = ISS claims["func"] = "user" claims["userId"] = user.UserId claims["exp"] = time.Now().Add(time.Hour * tokenLifetime).Unix() claims["identities"] = user.Identities claims["admin"] = user.Admin st, err := token.SignedString(Secret) if err != nil { return "", err } return st, nil }
验证解析Token的代码
// bearerToken should be "Bearer <JWT>" func VerifyUserToken(bearerToken string) (*model.UserClaims, bool) { strArr := strings.Split(bearerToken, " ") if len(strArr) != 2 || strArr[0] != "Bearer" { return nil, false } claims, ok := VerifyToken(strArr[1]) if ok && claims.Func != "user" { return nil, false } return claims, ok } func VerifyToken(tokenStr string) (*model.UserClaims, bool) { token, err := jwt.ParseWithClaims(tokenStr, &model.UserClaims{}, func (token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method") } return Secret, nil }) if err != nil { return nil, false } var ok bool var claims *model.UserClaims claims, ok = token.Claims.(*model.UserClaims) fmt.Println(claims.Admin) return claims, ok && token.Valid }
结构体定义
type User struct { UserId string `json:"userId"` Email string `json:"email"` Identities []IdentityNoPii `json:"identities"` Created uint64 `json:"created"` Admin bool `json:"admin"` } type UserClaims struct { User jwt.StandardClaims Func string `json:"func"` Sub string `json:"sub"` }
问题根源
生成Token时你将admin作为顶层声明字段,但解析用的UserClaims结构体中,Admin字段嵌套在匿名结构体User内。部分版本的JWT库在解析时,无法自动将顶层JWT声明映射到嵌套匿名结构体的字段,导致Admin被赋予默认值false。
修复方案
两种可行方案选其一即可:
方案1:将User字段移至UserClaims顶层
修改结构体,去掉嵌套直接包含所有字段,确保JWT顶层声明能直接匹配:
type UserClaims struct { UserId string `json:"userId"` Email string `json:"email"` Identities []IdentityNoPii `json:"identities"` Created uint64 `json:"created"` Admin bool `json:"admin"` jwt.StandardClaims Func string `json:"func"` Sub string `json:"sub"` }
方案2:生成Token时直接使用UserClaims结构体
保持结构体不变,修改生成逻辑,用目标结构体构建Claims,确保序列化与反序列化结构完全一致:
func GenerateUserToken(user model.User) (string, error) { claims := &model.UserClaims{ User: user, StandardClaims: jwt.StandardClaims{ Issuer: ISS, ExpiresAt: time.Now().Add(time.Hour * tokenLifetime).Unix(), }, Func: "user", } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(Secret) }
额外检查
- 确保使用最新稳定版JWT库(推荐
github.com/golang-jwt/jwt/v5,旧版github.com/dgrijalva/jwt-go已停止维护); - 生成Token前可加日志确认
user.Admin确实为true。
内容的提问来源于stack exchange,提问作者jnasworld223
相关产品推荐
相关产品推荐

