0

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

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"
}

cookieaccess_token是使用 的值创建的eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NfdXVpZCI6ImFlMmQ4MDlhLTNhZDgtNDgwNS1iMjZlLWUyYWMwNTYyMjZhZiIsImF1dGhvcml6ZWQiOnRydWUsImV4cCI6MTY0MTE4NTg5MCwicGVybWlzc2lvbiI6InVzZXIiLCJzdWIiOiJ0ZXN0OEBleGFtcGxlLmNvbSJ9.cXzkNoDb1XKmt_quQ4ONvDcXfmPrBjt4umG38a1xwqA ,如果检查 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应该能够返回完整的有效负载数据,就像从这样的登录函数创建的数据

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

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

4

1 回答 1

0

终于想通了

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
    })

然后分配ad := &AccessDetails{}如下的元素

    payload := token.Claims.(jwt.MapClaims)

    ad.Email = payload["sub"].(string)
    ad.AccessUuid = payload["access_uuid"].(string)
于 2022-01-03T23:02:16.807 回答