如何在Go语言中基于RSA密钥对验证JWT令牌并加载到自定义结构体
Go 基于RSA密钥对的JWT校验及结构体映射实现
库选型说明
- Go 生态没有强制规定的JWT“标准库”,
lestrrat-go/jwx是长期维护稳定、完整覆盖JWT系列规范的主流生产级选型,在签名算法覆盖、API设计一致性上更适合长期项目使用。 - 同生态的另一常见选型为
golang-jwt/jwt,可根据项目依赖习惯选择,核心校验逻辑流程基本一致。
核心实现步骤
- 解析PEM格式的RSA公钥内容,注意公钥字符串必须包含完整的PEM头尾标识(如
-----BEGIN PUBLIC KEY-----、-----END PUBLIC KEY-----),缺失标识会直接解析失败。 - 加载公钥作为校验密钥,对传入的JWT令牌执行签名合法性校验,同步完成内置声明(签发时间、过期时间)的自动校验。
- 将校验通过的令牌内的自定义声明,映射到预先定义的结构体上。
完整可运行代码示例
package main import ( "crypto/x509" "encoding/pem" "errors" "fmt" "github.com/lestrrat-go/jwx/v2/jwt" ) type JwtData struct { AccessToken string `json:"access_token"` Iat int `json:"iat"` Exp int `json:"exp"` Sub string `json:"sub"` Iss string `json:"iss"` } func whatDoIDoHere(publicKeyString, tokenString string) (*JwtData, error) { // 解析PEM格式公钥 pemBlock, _ := pem.Decode([]byte(publicKeyString)) if pemBlock == nil { return nil, errors.New("公钥PEM格式非法") } pubKey, err := x509.ParsePKIXPublicKey(pemBlock.Bytes) if err != nil { return nil, fmt.Errorf("RSA公钥解析失败: %w", err) } // 校验并解析JWT,自动完成签名校验、过期时间等内置声明校验 keySet := jwt.NewMapKeySet() _ = keySet.Add(jwt.NewKeyFromMap(map[string]interface{}{ // 需和令牌签发时使用的RSA算法保持一致(如RS256/PS256) "alg": "RS256", "key": pubKey, })) token, err := jwt.Parse( []byte(tokenString), jwt.WithKeySet(keySet), ) if err != nil { return nil, fmt.Errorf("JWT令牌校验失败: %w", err) } // 将令牌声明映射到自定义结构体 var data JwtData if err := token.Claims(&data); err != nil { return nil, fmt.Errorf("结构体字段映射失败: %w", err) } return &data, nil } func main() { privateKeyString := "my_private_key" publicKeyString := "my_public_key" tokenString := "my_token_data" decryptedData, err := whatDoIDoHere(publicKeyString, tokenString) if err != nil { panic(err) } // 正常使用解析后的decryptedData即可 _ = decryptedData _ = privateKeyString }
关键注意事项
- 非对称JWT的使用逻辑不要混淆:私钥仅用于签发令牌,公钥仅用于校验令牌签名,无需在校验环节引入私钥内容。
- 校验时指定的签名算法必须和签发令牌时的算法完全一致,否则会触发算法不匹配的校验错误。
- 自定义结构体的JSON tag必须和令牌内的声明字段名完全匹配,否则会出现字段值为空的映射问题。
内容的提问来源于stack exchange,提问作者user14416704
相关产品推荐
相关产品推荐

