如何从使用gofiber-golang框架创建的cookie中获取jwt有效载荷数据



我有以下功能来创建一个服务器端HTTPOnly,该HTTPOnly使用v2版本"github.com/gofiber/fiber/v2" 的gofiber框架

func Signin(c *fiber.Ctx) error {
    
    type SigninData struct {
        Email  string `json:"email" xml:"email" form:"email"`
        Password string `json:"password" xml:"password" form:"password"`
    }
    data := SigninData{}
    if err := c.BodyParser(&data); err != nil {
        return err
    }
    var user models.User
    findUser := database.DB.Where("email = ?", data.Email).First(&user)
    if findUser == nil {
        c.Status(fiber.StatusBadRequest)
        return c.JSON(fiber.Map{
            "message": "Account not found",
        })
    }
    if err := user.ComparePassword(data.Password); err != nil {
        c.Status(fiber.StatusBadRequest)
        return c.JSON(fiber.Map{
            "message": "Invalid credentials",
        })
    }
    isSuperuser := database.DB.Where("email = ? AND is_superuser = ?", data.Email, true).First(&user).Error
    var scope string
    if errors.Is(isSuperuser, gorm.ErrRecordNotFound) {
        scope = "user"
    } else {
        scope = "admin"
    }
    token, err := middlewares.CreateTokens(user.Email, scope)
    if err != nil {
        c.Status(fiber.StatusBadRequest)
        return c.JSON(fiber.Map{
            "message": "Could not generate session tokens",
        })  
    }
    saveErr := middlewares.RedisStoreTokens(user.Email, token)
    if saveErr != nil {
        c.Status(fiber.StatusBadRequest)
        return c.JSON(fiber.Map{
            "message": "Could not save session to redis",
        })
    }
    tokens := map[string]string{
        "access_token":  token.AccessToken,
        "refresh_token": token.RefreshToken,
    }
    cookie := fiber.Cookie{
        Name: "access_token",
        Value: tokens["access_token"],
        Expires: time.Now().Add(time.Hour * 24),
        HTTPOnly: true,
        Secure:   true,
    }
    c.Cookie(&cookie)
    return c.JSON(fiber.Map{
        "access_token": tokens["access_token"],
        "refresh_token": tokens["refresh_token"],
        "token_type": "bearer",
    })
}

以下是它在签署时返回的内容

{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NfdXVpZCI6ImFlMmQ4MDlhLTNhZDgtNDgwNS1iMjZlLWUyYWMwNTYyMjZhZiIsImF1dGhvcml6ZWQiOnRydWUsImV4cCI6MTY0MTE4NTg5MCwicGVybWlzc2lvbiI6InVzZXIiLCJzdWIiOiJ0ZXN0OEBleGFtcGxlLmNvbSJ9.cXzkNoDb1XKmt_quQ4ONvDcXfmPrBjt4umG38a1xwqA",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWZyZXNoX3V1aWQiOiJhZTJkODA5YS0zYWQ4LTQ4MDUtYjI2ZS1lMmFjMDU2MjI2YWYrK3Rlc3Q4QGV4YW1wbGUuY29tIn0._6zOG65GmnwbWnpKaQb2LxuPIhKZGCzg9P62xoBds8U",
    "token_type": "bearer"
}

使用值eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NfdXVpZCI6ImFlMmQ4MDlhLTNhZDgtNDgwNS1iMjZlLWUyYWMwNTYyMjZhZiIsImF1dGhvcml6ZWQiOnRydWUsImV4cCI6MTY0MTE4NTg5MCwicGVybWlzc2lvbiI6InVzZXIiLCJzdWIiOiJ0ZXN0OEBleGFtcGxlLmNvbSJ9.cXzkNoDb1XKmt_quQ4ONvDcXfmPrBjt4umG38a1xwqA创建cookie access_token如果检查cookie的有效载荷数据,则得到以下

{
  "access_uuid": "ae2d809a-3ad8-4805-b26e-e2ac056226af",
  "authorized": true,
  "exp": 1641185890,
  "permission": "user",
  "sub": "test8@example.com"
}

所以现在我想要另一个功能,它将提取并能够抓取cookie中的所有这些有效载荷数据,这样我就可以在应用中使用它

这是我的一个功能,本应获取这些数据,但事情不起作用,gofiber没有记录任何错误,甚至很难对进行故障排除

type ClaimsWithScope struct {
    jwt.RegisteredClaims
    Scope string `json:"permissions"`
}
type AccessDetails struct {
    AccessUuid   string  `json:"access_uuid"`
    Email        string  `json:"email"`
}
type AccessDetailsClaims struct {
    jwt.RegisteredClaims
    Scope        string  `json:"permissions"`
    AccessUuid   string  `json:"access_uuid"`
    Authorized   string  `json:"authorized"`
}
...
...
...
func GetAccessDetails(c *fiber.Ctx) (*AccessDetails, error) {
    ad := &AccessDetails{}
    cookie := c.Cookies("access_token")
    var err error
    token, err := jwt.ParseWithClaims(cookie, &AccessDetailsClaims{}, func(token *jwt.Token) (interface{}, error) {
        return []byte(SecretKey), nil
    })
    if err != nil {
        return nil, err
    }
    payload := token.Claims.(*AccessDetailsClaims)
    ad.Email = payload.Subject
    ad.AccessUuid = payload.AccessUuid
    return ad, nil
}

我在这里做错了什么?ad应该能够返回完整的有效载荷数据,就像从像这个这样的signin函数创建的数据一样

{
  "access_uuid": "ae2d809a-3ad8-4805-b26e-e2ac056226af",
  "authorized": true,
  "exp": 1641185890,
  "permission": "user",
  "sub": "test8@example.com"
}

这样我就可以从中获取我需要的任何数据

终于找到了

func GetAccessDetails(c *fiber.Ctx) (*AccessDetails, error) {
    ad := &AccessDetails{}
    cookie := c.Cookies("access_token")
    var err error
    token, err := jwt.Parse(cookie, func(token *jwt.Token) (interface{}, error) {
        return []byte(os.Getenv("ACCESS_SECRET")), nil
    })
    if err != nil {
        return nil, err
    }
    payload := token.Claims.(jwt.MapClaims)
    ad.Email = payload["sub"].(string)
    ad.AccessUuid = payload["access_uuid"].(string)
    return ad, nil
}

因此,由于我使用mapClaims来创建令牌,所以我可以用这个获取它

token, err := jwt.Parse(cookie, func(token *jwt.Token) (interface{}, error) {
        return []byte(os.Getenv("ACCESS_SECRET")), nil
    })

然后分配CCD_ 5的元素如下

    payload := token.Claims.(jwt.MapClaims)
    ad.Email = payload["sub"].(string)
    ad.AccessUuid = payload["access_uuid"].(string)

最新更新