如何使用golang验证Keycloak生成的json令牌

bvjveswy  于 2023-04-27  发布在  Go
关注(0)|答案(1)|浏览(205)

我想使用golang验证一个json token,但我只看到错误Error parsing or validating token: key is of invalid type。下面是我的代码:

package main

import (
    "fmt"

    "github.com/dgrijalva/jwt-go"
)

func main() {
    // example token to validate
    tokenString := "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6MXdOWU9YVFRpd2RhQjJyS1NqNElrUG1YTDJHbXVTOVFRNERJeXpWbWlrIn0.eyJleHAiOjE2ODIxMTQ3MjgsImlhdCI6MTY4MjExNDQyOCwianRpIjoiZDE5NGZlMmEtZDUyOC00YjhhLWI3OWItODEwNDMxNWExNzIxIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy9BcnFncmlmbyIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJmOWExMTYxYi00YzhiLTRmM2MtODViYy0xYmM1MDE0MWFmNTYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIvKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGVmYXVsdC1yb2xlcy1hcnFncmlmbyIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJ3ZWItYXBwIjp7InJvbGVzIjpbInVtYV9wcm90ZWN0aW9uIl19LCJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJjbGllbnRJZCI6IndlYi1hcHAiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImNsaWVudEhvc3QiOiIxNzIuMTcuMC4xIiwicHJlZmVycmVkX3VzZXJuYW1lIjoic2VydmljZS1hY2NvdW50LXdlYi1hcHAiLCJjbGllbnRBZGRyZXNzIjoiMTcyLjE3LjAuMSJ9.vqFWx5mMESEMww8E5t1J8ZmoCw1R9qv1qlgaYaG7FQcd8B_sN223cDYMoqJF5y-Xv9zaJ094fUmyDtJHv-ZTkxw3R9AtjG0cCjqMxgBn1X2irlNYEmR5ZX73YXDUxY6XuABLyTGdh00bEcaUIyFR1Pver2UDjMf2okcV1FgEd0Z_94j4pjqtcY0nbsWIKnLoVoor7QV6ytWRpMG25DvrSVxciaOpogOHlUhaWtTfMz-mvfFg64i_S6rIuT84APnVe6weAuj92YS6bUzBif_gcgNeMdLrJChxWdPMK9G5mDAgLOqUv-X5fPOw1arigInV0nCJmKV7LG6Yc1UlDHdmiA"

    // define the secret key used to sign the token
    secretKey := []byte("P184S3h7Ugjl56l31qeJ4FKvmBB4iikc")

    // parse the token and validate it
    token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
        // validate the signing algorithm
        if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
            return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
        }

        // return the secret key
        return secretKey, nil
    })
    // check if there was an error parsing or validating the token
    if err != nil {
        fmt.Println("Error parsing or validating token:", err)
        return
    }

    // check if the token is valid
    if !token.Valid {
        fmt.Println("Invalid token")
        return
    }

    // print the claims of the token
    claims := token.Claims.(jwt.MapClaims)
    fmt.Println("Claims:", claims)
}

我不知道,但我想我弄错了。令牌的algRS256。我试图从keycloak上的领域获取公钥。

我做错了什么?

6uxekuva

6uxekuva1#

// define the secret key used to sign the token
secretKey := []byte("P184S3h7Ugjl56l31qeJ4FKvmBB4iikc")

这里的注解和变量名会引起误解。根据演示中的代码,这是用于验证令牌的公钥。
另一个问题是jwt.Parse期望keyFunc返回*rsa.PublicKey的示例。从Keycloak复制的公钥是base64编码的密钥,应该首先解析。下面的parseKeycloakRSAPublicKey演示了如何解析它。
以下是完整的demo:

package main

import (
    "crypto/rsa"
    "crypto/x509"
    "encoding/base64"
    "fmt"

    jwt "github.com/dgrijalva/jwt-go"
)

func main() {
    // example token to validate
    tokenString := "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6MXdOWU9YVFRpd2RhQjJyS1NqNElrUG1YTDJHbXVTOVFRNERJeXpWbWlrIn0.eyJleHAiOjE2ODIxMTQ3MjgsImlhdCI6MTY4MjExNDQyOCwianRpIjoiZDE5NGZlMmEtZDUyOC00YjhhLWI3OWItODEwNDMxNWExNzIxIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy9BcnFncmlmbyIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJmOWExMTYxYi00YzhiLTRmM2MtODViYy0xYmM1MDE0MWFmNTYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIvKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGVmYXVsdC1yb2xlcy1hcnFncmlmbyIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJ3ZWItYXBwIjp7InJvbGVzIjpbInVtYV9wcm90ZWN0aW9uIl19LCJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJjbGllbnRJZCI6IndlYi1hcHAiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImNsaWVudEhvc3QiOiIxNzIuMTcuMC4xIiwicHJlZmVycmVkX3VzZXJuYW1lIjoic2VydmljZS1hY2NvdW50LXdlYi1hcHAiLCJjbGllbnRBZGRyZXNzIjoiMTcyLjE3LjAuMSJ9.vqFWx5mMESEMww8E5t1J8ZmoCw1R9qv1qlgaYaG7FQcd8B_sN223cDYMoqJF5y-Xv9zaJ094fUmyDtJHv-ZTkxw3R9AtjG0cCjqMxgBn1X2irlNYEmR5ZX73YXDUxY6XuABLyTGdh00bEcaUIyFR1Pver2UDjMf2okcV1FgEd0Z_94j4pjqtcY0nbsWIKnLoVoor7QV6ytWRpMG25DvrSVxciaOpogOHlUhaWtTfMz-mvfFg64i_S6rIuT84APnVe6weAuj92YS6bUzBif_gcgNeMdLrJChxWdPMK9G5mDAgLOqUv-X5fPOw1arigInV0nCJmKV7LG6Yc1UlDHdmiA"

    // The base64-encoded public key downloaded from Keycloak.
    // The screenshot in the question shows the correct place to get it.
    // It's much longer than "P184S3h7Ugjl56l31qeJ4FKvmBB4iikc".
    base64EncodedPublicKey := `replaced with the public key downloaded from Keycloak`
    publicKey, err := parseKeycloakRSAPublicKey(base64EncodedPublicKey)
    if err != nil {
        panic(err)
    }

    token, err := jwt.Parse(tokenString, 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 the public key that is used to validate the token.
        return publicKey, nil
    })
    if err != nil {
        fmt.Println("Error parsing or validating token:", err)
        return
    }

    if !token.Valid {
        fmt.Println("Invalid token")
        return
    }

    claims := token.Claims.(jwt.MapClaims)
    fmt.Println("Claims:", claims)
}

func parseKeycloakRSAPublicKey(base64Encoded string) (*rsa.PublicKey, error) {
    buf, err := base64.StdEncoding.DecodeString(base64Encoded)
    if err != nil {
        return nil, err
    }
    parsedKey, err := x509.ParsePKIXPublicKey(buf)
    if err != nil {
        return nil, err
    }
    publicKey, ok := parsedKey.(*rsa.PublicKey)
    if ok {
        return publicKey, nil
    }
    return nil, fmt.Errorf("unexpected key type %T", publicKey)
}

相关问题