我得到了"密钥是无效类型";当我尝试在中间件中验证基于Cognito的JWT时。目前,当Fiber应用程序正在设置时,我设置了这样的中间软件:
// read the "jwks.json" that I got from AWS locally
signingKey, err := ioutil.ReadFile("./jwks.json")
if err != nil {
log.Fatal("Error when opening file: ", err)
}
// pass in the signing key when middle ware is created
app.Get("/api", middleware.Protected(signingKey), handlers.ReadSomeData)
然后我的中间件看起来是这样的,其中大部分来自Go Fiber的JWT示例回购。
func Protected(signingKey []byte) func(*fiber.Ctx) error {
return jwtware.New(jwtware.Config{
SigningKey: signingKey,
ErrorHandler: jwtError,
SigningMethod: "RS256",
})
}
func jwtError(c *fiber.Ctx, err error) error {
if err.Error() == "Missing or malformed JWT" {
c.Status(fiber.StatusBadRequest)
return c.JSON(fiber.Map{"status": "error", "message": err.Error(), "data": nil})
} else {
c.Status(fiber.StatusUnauthorized)
return c.JSON(fiber.Map{"status": "error", "message": err.Error(), "data": nil})
}
}
在回答之后,我尝试使用";签名键";param,但有一个类型不匹配,所以我最终读取了jwks-json文件,如下所示:
func Protected() func(*fiber.Ctx) error {
signingKey, err := os.ReadFile("./jwks.json")
if err != nil {
}
x := make(map[string]interface{})
json.Unmarshal(signingKey, &x)
return jwtware.New(jwtware.Config{
SigningKeys: x,
ErrorHandler: jwtError,
SigningMethod: "RS256",
})
}
然而,现在我的错误是";意外的jwt密钥id=XXXXXXXXXXXXX";
事实证明,如果您为fiber提供一个指向键的url,那么它有一个内置的功能来提取jwks.json数据。也许还有一种方法可以让它加载一个本地文件,但使用AWS密钥,你通常不会这样做——密钥可能会根据你在生产或测试中的环境而变化。
您需要知道您的AWS用户池区域和该用户池的ID。这通常在用户池设置视图中提供,但您可以根据AWS文档中提供的以下示例轻松获得:
https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json
有关更多信息,请参阅:AWS:验证JSON web令牌
下面是一个简单的例子,让它与AWS Cognito JWT url:一起工作
authMiddleware := jwtware.New(jwtware.Config{
TokenLookup: "header:Authorization",
AuthScheme: "Bearer",
KeySetURLs: []string{
"https://cognito-idp.some-region-1.amazonaws.com/some-region-1_MYUserPoolId/.well-known/jwks.json",
},
})
// Match any route
app.Use(authMiddleware, func(c *fiber.Ctx) error {
return c.SendString("🥇 Yay!")
})
log.Fatal(app.Listen(":3000"))
你现在应该可以用这样的请求来测试它:
curl --location --request GET 'http://127.0.0.1:3000'
--header 'Authorization: Bearer MyAWSJWTToken..'
或者使用任何HTTP客户端(如Postman(。您必须在授权标头中提供JWT。
另请参阅:
- JWT光纤中间件
github.com/gofiber/jwt
项目使用github.com/MicahParks/keyfunc
作为JWK Set客户端。自github.com/MicahParks/keyfunc
预发布以来,它也没有对其进行更新。由于已知的错误,我建议不要在当前状态下使用该项目。
下面是一个从AWS Cognito解析JWK集的示例,然后使用该集中的密钥直接从github.com/Micahparks/keyfunc
项目解析JWT:
以下是github.com/MicahParks/keyfunc
项目的链接:链接
package main
import (
"fmt"
"log"
"time"
"github.com/golang-jwt/jwt/v4"
"github.com/MicahParks/keyfunc"
)
func main() {
// Get the JWKS URL from your AWS region and userPoolId.
//
// See the AWS docs here:
// https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
regionID := "" // TODO Get the region ID for your AWS Cognito instance.
userPoolID := "" // TODO Get the user pool ID of your AWS Cognito instance.
jwksURL := fmt.Sprintf("https://cognito-idp.%s.amazonaws.com/%s/.well-known/jwks.json", regionID, userPoolID)
// Create the keyfunc options. Use an error handler that logs. Refresh the JWKS when a JWT signed by an unknown KID
// is found or at the specified interval. Rate limit these refreshes. Timeout the initial JWKS refresh request after
// 10 seconds. This timeout is also used to create the initial context.Context for keyfunc.Get.
options := keyfunc.Options{
RefreshErrorHandler: func(err error) {
log.Printf("There was an error with the jwt.KeyfuncnError: %s", err.Error())
},
RefreshInterval: time.Hour,
RefreshRateLimit: time.Minute * 5,
RefreshTimeout: time.Second * 10,
RefreshUnknownKID: true,
}
// Create the JWKS from the resource at the given URL.
jwks, err := keyfunc.Get(jwksURL, options)
if err != nil {
log.Fatalf("Failed to create JWKS from resource at the given URL.nError: %s", err.Error())
}
// Get a JWT to parse.
jwtB64 := "eyJraWQiOiJmNTVkOWE0ZSIsInR5cCI6IkpXVCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJLZXNoYSIsImF1ZCI6IlRhc2h1YW4iLCJpc3MiOiJqd2tzLXNlcnZpY2UuYXBwc3BvdC5jb20iLCJleHAiOjE2MTkwMjUyMTEsImlhdCI6MTYxOTAyNTE3NywianRpIjoiMWY3MTgwNzAtZTBiOC00OGNmLTlmMDItMGE1M2ZiZWNhYWQwIn0.vetsI8W0c4Z-bs2YCVcPb9HsBm1BrMhxTBSQto1koG_lV-2nHwksz8vMuk7J7Q1sMa7WUkXxgthqu9RGVgtGO2xor6Ub0WBhZfIlFeaRGd6ZZKiapb-ASNK7EyRIeX20htRf9MzFGwpWjtrS5NIGvn1a7_x9WcXU9hlnkXaAWBTUJ2H73UbjDdVtlKFZGWM5VGANY4VG7gSMaJqCIKMxRPn2jnYbvPIYz81sjjbd-sc2-ePRjso7Rk6s382YdOm-lDUDl2APE-gqkLWdOJcj68fc6EBIociradX_ADytj-JYEI6v0-zI-8jSckYIGTUF5wjamcDfF5qyKpjsmdrZJA"
// Parse the JWT.
token, err := jwt.Parse(jwtB64, jwks.Keyfunc)
if err != nil {
log.Fatalf("Failed to parse the JWT.nError: %s", err.Error())
}
// Check if the token is valid.
if !token.Valid {
log.Fatalf("The token is not valid.")
}
log.Println("The token is valid.")
// End the background refresh goroutine when it's no longer needed.
jwks.EndBackground()
}