Jiew Meng
Jiew Meng

Reputation: 88337

How to use golang 1.7 context with http.Request (for Authentication)

I have an IsAuthenticated function to check if the request is authenticated (checking the JWT in the Authorization header)

func IsAuthenticated(a *framework.AppContext, r *http.Request) (int, error) {
  // ... do authentication. user is authenticated User object
  ctx := context.WithValue(r.Context(), "user", user)
  r = r.WithContext(ctx) 
  return 200, nil
} 

I find that it appears that r = r.WithContext(ctx) does not override the request object? How should I implement this? Do I need to requrn a request instead?

Upvotes: 5

Views: 1871

Answers (1)

captncraig
captncraig

Reputation: 23118

It is not clear to me exactly how what you show is a "middleware", or how it is being executed. Since you are only changing your local variable r, and never giving that to anyone else, there is no way your change wil be visible outside your function.

There have been a variety of middleware flavors in the go landscape, but since go 1.7 I have seen a lot more moving towards middleware functions of the form:

func IsAuthenticated(next http.Handler) http.Handler{
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
       //authenticate. Set cookies.
       //403 if not authenticated, etc.
       ctx := context.WithValue(r.Context(), "user",u)
       next(w,r.WithContext(ctx))
    })
}

This can be used to chain handlers together like so:

http.Handle("/foo/bar", IsAuthenticated(myHandler))

(or use something like alice to make chaining middlewares even easier.)

This way, when myHandler gets invoked, it will have the new request created by IsAuthenticated, and it can fetch the user with something like:

user := r.Context().Get("user").(*User)

Upvotes: 7

Related Questions