使用 Go Fiber 中间件进行 AWS Cognito JWT 验证 (获取"key is of invalid type" )



我得到了"密钥是无效类型";当我尝试在中间件中验证基于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()
}

相关内容

  • 没有找到相关文章

最新更新