gqlgen 从解析器设置 cookie
gqlgen Set cookie from resolver
我正在使用 gin 和 gqlgen。
我需要从解析器设置 cookie,但解析器中只有来自 graphQL 的上下文和输入。
此问题已在 github 中得到解答。
但是这个不同,因为我无法更改 ctx.Writer.Write
,当您尝试传入 ctx.Next
时什么也没有。因为 gin
不是那样工作的。
func (r *mutationResolver) Login(ctx context.Context, email string, password string) (bool, error) {
// You need ctx.Writer to set a cookie and can't access that from here
}
我已经解决了这个问题,我想在下面回答我自己的问题。
简答
服务器端cookie说明:cookie是通过headers设置的,浏览器就是这样理解你要设置cookie的,需要ctx.Writer
写headers。最后,“您想在解析器中访问 ctx.Writer
”。
你的中间件中有一个ctx
(在我的例子中它是杜松子酒,它是ctx.Request.Context()
),你有一个ctx.Writer
,这是你需要写的到您的 headers 并设置 cookie。
你应该把你的 ctx.Writer
放到你的 ctx.Request.Context()
中,因为你的 ctx.Request
正转到你的解析器,而不是 hole ctx!
然后你就可以访问你的作家了。
完整答案
在 middleware
中你必须构建一个结构 object,将 ctx.Writer
传递给它并设置一个指向 ctx.Request.Context
的指针并设置一个方法来为你设置 cookie。
type CookieAccess struct {
Writer http.ResponseWriter
UserId uint64
IsLoggedIn bool
}
// method to write cookie
func (this *CookieAccess) SetToken(token string) {
http.SetCookie(this.Writer, &http.Cookie{
Name: cookieName,
Value: token,
HttpOnly: true,
Path: "/",
Expires: time.Now().Add(token_expire),
})
}
在你的 middleware
:
func extractUserId(ctx *gin.Context) (uint64, error) {
c, err := ctx.Request.Cookie(cookieName)
if err != nil {
return 0, errors.New("There is no token in cookies")
}
userId, err := ParseToken(c.Value)
if err != nil {
return 0, err
}
return userId, nil
}
func setValInCtx(ctx *gin.Context, val interface{}) {
newCtx := context.WithValue(ctx.Request.Context(), cookieAccessKeyCtx, val)
ctx.Request = ctx.Request.WithContext(newCtx)
}
func Middleware() gin.HandlerFunc {
return func(ctx *gin.Context) {
cookieA := CookieAccess{
Writer: ctx.Writer,
}
// &cookieA is a pointer so any changes in future is changing cookieA is context
setValInCtx(ctx, &cookieA)
userId, err := extractUserId(ctx)
if err != nil {
cookieA.IsLoggedIn = false
ctx.Next()
return
}
cookieA.UserId = userId
cookieA.IsLoggedIn = true
// calling the actual resolver
ctx.Next()
// here will execute after resolver and all other middlewares was called
// so &cookieA is safe from garbage collector
}
}
您必须在解析器中调用此函数。
它得到 ctx
并返回 &cookieA
func GetCookieAccess(ctx context.Context) *CookieAccess {
return ctx.Value(cookieAccessKeyCtx).(*CookieAccess)
}
最后在您的 Login
解析器中:
CA := security.GetCookieAccess(ctx)
CA.SetToken(token)
CA.UserId = userId
我希望这会对某人有所帮助:)))
我正在使用 gin 和 gqlgen。
我需要从解析器设置 cookie,但解析器中只有来自 graphQL 的上下文和输入。
此问题已在 github 中得到解答。
但是这个不同,因为我无法更改 ctx.Writer.Write
,当您尝试传入 ctx.Next
时什么也没有。因为 gin
不是那样工作的。
func (r *mutationResolver) Login(ctx context.Context, email string, password string) (bool, error) {
// You need ctx.Writer to set a cookie and can't access that from here
}
我已经解决了这个问题,我想在下面回答我自己的问题。
简答
服务器端cookie说明:cookie是通过headers设置的,浏览器就是这样理解你要设置cookie的,需要ctx.Writer
写headers。最后,“您想在解析器中访问 ctx.Writer
”。
你的中间件中有一个ctx
(在我的例子中它是杜松子酒,它是ctx.Request.Context()
),你有一个ctx.Writer
,这是你需要写的到您的 headers 并设置 cookie。
你应该把你的 ctx.Writer
放到你的 ctx.Request.Context()
中,因为你的 ctx.Request
正转到你的解析器,而不是 hole ctx!
然后你就可以访问你的作家了。
完整答案
在 middleware
中你必须构建一个结构 object,将 ctx.Writer
传递给它并设置一个指向 ctx.Request.Context
的指针并设置一个方法来为你设置 cookie。
type CookieAccess struct {
Writer http.ResponseWriter
UserId uint64
IsLoggedIn bool
}
// method to write cookie
func (this *CookieAccess) SetToken(token string) {
http.SetCookie(this.Writer, &http.Cookie{
Name: cookieName,
Value: token,
HttpOnly: true,
Path: "/",
Expires: time.Now().Add(token_expire),
})
}
在你的 middleware
:
func extractUserId(ctx *gin.Context) (uint64, error) {
c, err := ctx.Request.Cookie(cookieName)
if err != nil {
return 0, errors.New("There is no token in cookies")
}
userId, err := ParseToken(c.Value)
if err != nil {
return 0, err
}
return userId, nil
}
func setValInCtx(ctx *gin.Context, val interface{}) {
newCtx := context.WithValue(ctx.Request.Context(), cookieAccessKeyCtx, val)
ctx.Request = ctx.Request.WithContext(newCtx)
}
func Middleware() gin.HandlerFunc {
return func(ctx *gin.Context) {
cookieA := CookieAccess{
Writer: ctx.Writer,
}
// &cookieA is a pointer so any changes in future is changing cookieA is context
setValInCtx(ctx, &cookieA)
userId, err := extractUserId(ctx)
if err != nil {
cookieA.IsLoggedIn = false
ctx.Next()
return
}
cookieA.UserId = userId
cookieA.IsLoggedIn = true
// calling the actual resolver
ctx.Next()
// here will execute after resolver and all other middlewares was called
// so &cookieA is safe from garbage collector
}
}
您必须在解析器中调用此函数。
它得到 ctx
并返回 &cookieA
func GetCookieAccess(ctx context.Context) *CookieAccess {
return ctx.Value(cookieAccessKeyCtx).(*CookieAccess)
}
最后在您的 Login
解析器中:
CA := security.GetCookieAccess(ctx)
CA.SetToken(token)
CA.UserId = userId
我希望这会对某人有所帮助:)))