Reputation: 449
I am trying to extract user_id in token authentication middleware and pass it to gqlgen's graphql resolver function (to populate created_by and updated_by columns of GraphQL schema). Authentication part works without any problems.
The Gin middleware:
var UID = "dummy"
func TokenAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
err := auth.TokenValid(c.Request)
if err != nil {
c.JSON(http.StatusUnauthorized, "You need to be authorized to access this route")
c.Abort()
return
}
//
UID, _ = auth.ExtractTokenID(c.Request)
//c.Set("user_id", UID)
c.Next()
}
}
func GetUID() string {
return UID
}
The graphql resolver:
var ConstID = middleware.GetUID()
func (r *mutationResolver) CreateFarmer(ctx context.Context, input model.NewFarmer) (*model.Farmer, error) {
//Fetch Connection and close db
db := model.FetchConnection()
defer db.Close()
//var ConstID, _ = uuid.NewRandom()
log.Println(ctx)
farmer := model.Farmer{Name: input.Name, Surname: input.Surname, Dob: input.Dob, Fin: input.Fin, PlotLocLat: input.PlotLocLat, PlotLocLong: input.PlotLocLong, CreatedAt: time.Now(), UpdatedAt: time.Now(), CreatedBy: ConstID, UpdatedBy: ConstID}
db.Create(&farmer)
return &farmer, nil
}
Here, I tried to do it using global variable UID, but UID's value is not getting updated in the middleware, and as a result, I'm getting "dummy" values in CreatedBy
and UpdatedBy
columns. I understand that the use of global variables is discouraged and I am open to other ideas. Thanks
Upvotes: 4
Views: 4082
Reputation: 34704
The accepted answer didn't work for me. Digging through Gin source code told me I need to either use an engine where ContextWithFallback
is true
, or simply use c.Set()
. If the key is a string, ctx.Value()
will look it up in gin's context c.Keys
and return it, even if accessing as context.Context
and not *gin.Context
.
So for me, this worked:
func TokenAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
UID := // ... get the UID somehow
c.Set("user_id", UID)
c.Next()
}
}
// ...
func (r *mutationResolver) CreateFarmer(ctx context.Context, input model.NewFarmer) (*model.Farmer, error) {
UID, _ := ctx.Value("user_id").(string)
// ...
}
I'm not sure why ContextWithFallback
was false
for me, but I like the result better anyway as it's simpler to read.
This applies to gin 1.8.1.
Upvotes: 1
Reputation: 44827
Propagate the value with context.Context
.
If you are using gqlgen, you have to remember that the context.Context
instance passed to resolver functions comes from the *http.Request
(assuming that you set up the integration as recommended in gqlgen's documentation).
Therefore with Go-Gin you should be able to do this with some additional plumbing:
func TokenAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
UID := // ... get the UID somehow
ctx := context.WithValue(c.Request.Context(), "user_id", UID)
c.Request = c.Request.WithContext(ctx)
c.Next()
}
}
And then you get the value in your resolver normally:
func (r *mutationResolver) CreateFarmer(ctx context.Context, input model.NewFarmer) (*model.Farmer, error) {
UID, _ := ctx.Value("user_id").(string)
// ...
}
An example (without Gin though) is also available here
Upvotes: 5