美文网首页
Golang Jwt key is of invalid typ

Golang Jwt key is of invalid typ

作者: 布衣码农 | 来源:发表于2021-08-06 17:26 被阅读0次

    golang-jwt/jwt key is of invalid type 错误的解决方法

    起因:

    无意中在github上看到dgrijalva/jwt-go已经不在维护了,而是替换成了golang-jwt/jwt,所以考虑更新一下新的jwt包,期间各种复杂,因为只是扫了一眼jwt的源码,以为没什么太大改动,所以以后还是得多看源码包,特此更新一篇笔记

    传送门:新版本go-jwt

    直接上源代码

    package jwt
    
    func GetToken(Id string) (string, error) {
        c := MyClaims{
            jwt.StandardClaims{
                Id : Id,
                ExpiresAt: time.Now().Add(TokenExpiration).Unix(),
            },
        }
            
      // 其实问题出在这里 这里会有很多选项 
      // 例如 ParseRSAPrivateKeyFromPEM rsa pkcs8的私钥解析
      // ParseEdPrivateKeyFromPEM   ed25519 pkcs8的私钥解析
      // 还有我用的 ParseECPrivateKeyFromPEM ecdsa pkcs8的私钥解析
      // 这个方法的目的是还原private 对应算法的[]byte 数据
        priKey, err := jwt.ParseECPrivateKeyFromPEM(privateKey)
        if err != nil {
            return "xxxx", err
        }
    
        token := jwt.NewWithClaims(jwt.SigningMethodES256, c)
        return token.SignedString(priKey)
    }
    
    

    我们来看一下 token.SignedString(priKey) 的源码

    // Get the complete, signed token 获取一个已签名的token
    func (t *Token) SignedString(key interface{}) (string, error) {
        var sig, sstr string
        var err error
      // 生成签名这里不用管
        if sstr, err = t.SigningString(); err != nil {
            return "", err
        }
      // 主要看这里t.Method.Sign 这里是一个接口
        if sig, err = t.Method.Sign(sstr, key); err != nil {
            return "", err
        }
        return strings.Join([]string{sstr, sig}, "."), nil
    }
    
    // t.Method.Sign --> 接口
    type SigningMethod interface {
        Verify(signingString, signature string, key interface{}) error  // 验签
        Sign(signingString string, key interface{}) (string, error)     // 签名
        Alg() string                                                        // 签名的hash方式 例如HS256
    }
    
    // 那么 SignedString 的这段代码就是加签的流程
    // 在最上面的代码块 GetToken 中  我使用的是 jwt.SigningMethodES256
    // 这个是看一个网上的demo 写的 所以这里也是跟 ParseECPrivateKeyFromPEM 保持一致的 
    // 也就是说可以有很多加密方式的选择 比如 以下相匹配的
    // 也就是说jwt/xxx_utils.go ParseXXXPublicKeyFromPEM 
    // 对应 jwt/xxx.go 下的 SigningMethodXXXX SigningMethodXXX
    // 例如 rsa 方式加签 就是 jwt/rsa_utils.go ParseRSAPrivateKeyFromPEMWithPassword / ParseRSAPublicKeyFromPEM 方法 
    // 对应 jwt/rsa.go 下的集中加签方式
    //  SigningMethodRS256 *SigningMethodRSA
    //  SigningMethodRS384 *SigningMethodRSA
    //  SigningMethodRS512 *SigningMethodRSA
    if sig, err = t.Method.Sign(sstr, key); err != nil {
            return "", err
    }
    
    
    
    
    

    以jwt.SigningMethodES256为例

    // Implements the Sign method from SigningMethod
    // For this signing method, key must be an ecdsa.PrivateKey struct
    func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) {
        // Get the key
        var ecdsaKey *ecdsa.PrivateKey // SigningMethodES256 需要的是 ecdsa 加签算法的私钥
                                                                    // 所以 再遇到 key is of invalid type 这个问题 直接考虑加密方式是否不匹配
        switch k := key.(type) {
        case *ecdsa.PrivateKey:
            ecdsaKey = k
        default:
            return "", ErrInvalidKeyType
        }
    
        // Create the hasher
        if !m.Hash.Available() {
            return "", ErrHashUnavailable
        }
    
        hasher := m.Hash.New()
        hasher.Write([]byte(signingString))
    
        // Sign the string and return r, s
        if r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, hasher.Sum(nil)); err == nil {
            curveBits := ecdsaKey.Curve.Params().BitSize
    
            if m.CurveBits != curveBits {
                return "", ErrInvalidKey
            }
    
            keyBytes := curveBits / 8
            if curveBits%8 > 0 {
                keyBytes += 1
            }
    
            // We serialize the outputs (r and s) into big-endian byte arrays
            // padded with zeros on the left to make sure the sizes work out.
            // Output must be 2*keyBytes long.
            out := make([]byte, 2*keyBytes)
            r.FillBytes(out[0:keyBytes]) // r is assigned to the first half of output.
            s.FillBytes(out[keyBytes:])  // s is assigned to the second half of output.
    
            return EncodeSegment(out), nil
        } else {
            return "", err
        }
    }
    

    以下附上生成ecdsa的私钥生成方法,其他算法同理自行处理吧

    package main
    
    import (
        "crypto/ecdsa"
        "crypto/elliptic"
        "crypto/rand"
        "crypto/x509"
        "encoding/base64"
        "fmt"
    )
    
    func generateEcdsaPrivateKey() (*ecdsa.PrivateKey, error) {
        return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    }
    
    func generatePkcs8PrivateKey(privateKey *ecdsa.PrivateKey) ([]byte, error) {
        return x509.MarshalPKCS8PrivateKey(privateKey)
    }
    
    func main() {
    
        key, err := generateEcdsaPrivateKey()
        if err != nil {
            panic(err)
        }
    
        pkcs8PrivateKey, err := generatePkcs8PrivateKey(key)
        if err != nil {
            panic(err)
        }
    
        privateKeyString := base64.StdEncoding.EncodeToString(pkcs8PrivateKey)
        base64PriKey := FormatPrivateKeyFromString(privateKeyString)
        fmt.Println(base64PriKey)
    }
    
    func  FormatPrivateKeyFromString(privateKey string) string{
        return fmt.Sprintf("-----BEGIN RSA PRIVATE KEY-----\n%s\n-----END RSA PRIVATE KEY-----", privateKey)
    }
    
    

    相关文章

      网友评论

          本文标题:Golang Jwt key is of invalid typ

          本文链接:https://www.haomeiwen.com/subject/zqqivltx.html