golang JWT 无签名。 “加密/rsa:验证错误”
Posted
技术标签:
【中文标题】golang JWT 无签名。 “加密/rsa:验证错误”【英文标题】:golang JWT No Signature. "crypto/rsa: verification error" 【发布时间】:2015-09-20 15:01:40 【问题描述】:我正在使用JWT。这就是我创建令牌的方式。
func createToken(user User) (string, error)
token := jwt.New(jwt.GetSigningMethod("RS256"))
token.Claims["Name"] = user.Name
token.Claims["Email"] = user.Email
//token.Claims["ExpDate"] = time.Now().Add(time.Hour * 1).Unix()
tokenString, err := token.SignedString([]byte(config.PrivateKey))
if err != nil
return "", err
return tokenString, nil
这就是我验证令牌的方式。
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface, error)
return []byte(config.PublicKey), nil
)
我用这个 python 代码生成了我的公钥和私钥
from Crypto.PublicKey import RSA
private = RSA.generate(1024)
public = private.publickey()
priv = private.exportKey()
pub = public.exportKey()
我收到crypto/rsa: verification error
。当我打印解析的令牌时,一切看起来都很好,除了 token.Valid
是假的,token.Signature
是空的。
type Token struct
Raw string // The raw token. Populated when you Parse a token
Method SigningMethod // The signing method used or to be used
Header map[string]interface // The first segment of the token
Claims map[string]interface // The second segment of the token
Signature string // The third segment of the token. Populated when you Parse a token
Valid bool // Is the token valid? Populated when you Parse/Verify a token
tokenString--> eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJFbWFpbCI6InRlc3RAaG90bWFpbC5jb20iLCJOYW1lIjoidGVzdE5hbWUifQ.fgd1h4LB1zzAiPFLKMOJrQu12rTLeXBDKHdnqiNc04NRn-1v7cHEQpDNawvScMIGrcQLbZo6WrldZQT9ImYWpUyy3CcD2uMO95I5PN6aXOSPb26nNGQpmIi1HNZrq5359hKZ6BWEJnW9iTg7RgmMvZGmIqlGLsOY2a6UiiwBsI0
token.Raw--> eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJFbWFpbCI6InRlc3RAaG90bWFpbC5jb20iLCJOYW1lIjoidGVzdE5hbWUifQ.fgd1h4LB1zzAiPFLKMOJrQu12rTLeXBDKHdnqiNc04NRn-1v7cHEQpDNawvScMIGrcQLbZo6WrldZQT9ImYWpUyy3CcD2uMO95I5PN6aXOSPb26nNGQpmIi1HNZrq5359hKZ6BWEJnW9iTg7RgmMvZGmIqlGLsOY2a6UiiwBsI0
token.Header--> map[alg:RS256 typ:JWT]
token.Claims--> map[Email:test@hotmail.com Name:testName]
token.Signature-->
token.Valid--> false
PS:我没有任何 SSL 证书。
【问题讨论】:
我强烈建议不要对 JSON Web 令牌使用 RSA(尤其是 1024 位密钥)。与仅使用jwt.GetSigningMethod("HS256")
(即 HMAC-SHA-256)相比,它确实没有提供实际的好处。 RSA 更容易出错。
@elithrar RSA vs HMAC ~ 公钥 vs 对称密钥;哪个更好取决于用例。 RSA 以何种方式“更容易出错”? JWT 库应该完成繁重的工作。
HMAC-SHA-256 很简单:你提供一个密钥,它会 MAC 化它。 RSA 更依赖于密钥强度(1024 不会削减它),最近的许多 JWT 漏洞都与 RSA 密钥有关,并且它增加了更多的复杂性(解析证书/私钥。除非您对客户端有一些迫切需要用你的公钥自我验证令牌,几乎没有什么收获。
@elithrar 有些用例需要与客户端验证令牌无关的公钥算法,例如依赖方为第三方的情况下。您不能向第三方提供您的 HMAC 机密。提问者没有说明他们生成的令牌是如何使用的。
很清楚。我想说的是“如果您必须询问如何生成 RSA 密钥并将它们与 SSL 混为一谈,那么您很可能不需要使用 RSA 密钥。”这些用例通常定义明确(正如您所指出的)。带有 React 或 Angular 的 SPA 的 JWT 不需要 RSA 签名的 JWT。
【参考方案1】:
这对我有用。我使用这些命令生成了 private.pem 和 public.pem。
openssl genrsa -des3 -out private.pem 1024
openssl rsa -in private.pem -outform PEM -pubout -out public.pem
代码:
package main
import (
"fmt"
"github.com/dgrijalva/jwt-go"
"io/ioutil"
"log"
"time"
)
//Claims can have user id.. etc for Identification purpose
type AppClaims struct
UserId string `json:"userId"`
jwt.StandardClaims
var (
privateKey []byte
publicKey []byte
err error
)
const (
longForm = "Jan 2, 2006 at 3:04pm (MST)"
)
func errLog(err error)
if err != nil
log.Fatal("Error:", err.Error())
func init()
privateKey, err = ioutil.ReadFile("../private.pem")
errLog(err)
publicKey, err = ioutil.ReadFile("../public.pem")
errLog(err)
func jwtTokenGen() (interface, error)
privateRSA, err := jwt.ParseRSAPrivateKeyFromPEM(privateKey)
if err != nil
return nil, err
claims := AppClaims
"RAJINIS*",
jwt.StandardClaims
ExpiresAt: time.Now().Add(time.Minute * 15).Unix(),
Issuer: "test",
,
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
ss, err := token.SignedString(privateRSA)
return ss, err
func jwtTokenRead(inToken interface) (interface, error)
publicRSA, err := jwt.ParseRSAPublicKeyFromPEM(publicKey)
if err != nil
return nil, err
token, err := jwt.Parse(inToken.(string), func(token *jwt.Token) (interface, error)
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
return publicRSA, err
)
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid
return claims, nil
else
return nil, err
func getTokenRemainingValidity(timestamp interface) int
expireOffset := 0
if validity, ok := timestamp.(float64); ok
tm := time.Unix(int64(validity), 0)
remainder := tm.Sub(time.Now())
if remainder > 0
fmt.Println(remainder)
return int(remainder.Seconds()) + expireOffset
return expireOffset
func main()
signedString, err := jwtTokenGen()
fmt.Println(signedString, err)
claims, err := jwtTokenRead(signedString)
if err != nil
errLog(err)
claimValue := claims.(jwt.MapClaims)
fmt.Println(claimValue["iss"], claimValue["exp"], claimValue["userId"])
// t, _ := time.Parse(longForm, string(claimValue["exp"].(float64)))
fmt.Println(getTokenRemainingValidity(claimValue["exp"]))
【讨论】:
以上是关于golang JWT 无签名。 “加密/rsa:验证错误”的主要内容,如果未能解决你的问题,请参考以下文章