1

我正在使用杜松子酒和 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
}

我已经解决了这个问题,我想在下面回答我自己的问题。

4

1 回答 1

2

middleware 您必须构建一个结构对象,传递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

我希望这会对某人有所帮助:)))

于 2021-02-07T17:08:41.880 回答