
JWT 并不默认使用公私钥对进行签名;HS256 等 HMAC 算法仅依赖单一密钥(即“密钥”,非“私钥”),用于服务端自验证,而非数字签名意义上的身份确权。混淆签名算法类型是导致 signature is invalid 错误的常见根源。
jwt 并不默认使用公私钥对进行签名;hs256 等 hmac 算法仅依赖单一密钥(即“密钥”,非“私钥”),用于服务端自验证,而非数字签名意义上的身份确权。混淆签名算法类型是导致 `signature is invalid` 错误的常见根源。
在 JWT 规范中,签名算法决定了密钥的使用方式。你当前代码中存在两个关键误解:
错误地将 SigningMethodHS256 与 RSA 密钥配对使用
jwt.SigningMethodHS256 是基于哈希的消息认证码(HMAC-SHA256),它要求同一个共享密钥(secret key)同时用于签名和验签。它不接受公私钥对——传入 publicKey 给 HS256 的验证回调,本质上是在用一个 RSA 公钥去校验 HMAC 签名,必然失败。混淆了“签名目的”:JWT 常用于服务端完整性保护,而非第三方身份断言
HMAC 模式下,密钥必须严格保密(如环境变量或密钥管理服务),其设计目标是:只有持有该密钥的服务才能生成/验证有效 Token。这适用于单体或可信微服务场景。而 RSA(如 RS256)才真正启用非对称加密:私钥签名、公钥验签,适用于需向第三方(如 OAuth2 资源服务器)证明签发者身份的场景。
✅ 正确做法取决于你的安全需求:
-
若使用 HMAC(如 HS256),请统一使用同一 secret:
secret := []byte("your-super-secret-key") // 不是 RSA 私钥文件! // 签名 token := jwt.New(jwt.SigningMethodHS256) token.Claims = jwt.MapClaims{"Latitude": "25.000", "Longitude": "27.000"} tokenString, err := token.SignedString(secret) if err != nil { /* handle */ } // 验签(必须用相同 secret) parsedToken, err := jwt.Parse(tokenString, func(*jwt.Token) (interface{}, error) { return secret, nil // ← 关键:返回 secret,不是 publicKey }) -
若坚持使用 RSA(如 RS256),则需切换签名方法并正确加载密钥:
// 读取 PEM 格式私钥(签名用) privKey, _ := ioutil.ReadFile("demo.rsa") privateKey, _ := jwt.ParseRSAPrivateKeyFromPEM(privKey) // 读取 PEM 格式公钥(验签用) pubKey, _ := ioutil.ReadFile("demo.rsa.pub") publicKey, _ := jwt.ParseRSAPublicKeyFromPEM(pubKey) // 签名:使用 RS256 + 私钥 token := jwt.New(jwt.SigningMethodRS256) token.Claims = jwt.MapClaims{"Latitude": "25.000", "Longitude": "27.000"} tokenString, err := token.SignedString(privateKey) // 验签:使用公钥(注意:回调中返回 *rsa.PublicKey,非 []byte) parsedToken, err := jwt.Parse(tokenString, func(*jwt.Token) (interface{}, error) { return publicKey, nil // ← 类型为 *rsa.PublicKey })
⚠️ 注意事项:
- github.com/dgrijalva/jwt-go 已归档,推荐升级至 github.com/golang-jwt/jwt/v5(API 更安全、文档更完善);
- RSA 密钥需为 PEM 编码的 PKCS#1 或 PKCS#8 格式;若 ParseRSAPublicKeyFromPEM 失败,请检查公钥文件是否含 -----BEGIN PUBLIC KEY----- 头尾;
- 永远不要在客户端暴露签名密钥(无论 HMAC secret 还是 RSA 私钥);
- 生产环境务必使用强随机 secret(如 crypto/rand 生成 32 字节以上)或受信密钥管理服务(KMS)。
总结:JWT 的安全性始于算法与密钥的匹配。选 HS256 就用 secret;选 RS256 才用 RSA 密钥对。理解这一分界,是构建可信赖认证流程的第一步。










