If I use multiple middleware in gin what is the order in which they are executed - go

If I use multiple middleware and I want to use output of mw1 in mw2 using ctx.Set and ctx.Get is there any defined order in which middleware are executed?
func main() {
// Creates a router without any middleware by default
r := gin.New()
// Global middleware
// Logger middleware will write the logs to gin.DefaultWriter even you set with GIN_MODE=release.
// By default gin.DefaultWriter = os.Stdout
r.Use(mw1)
// Recovery middleware recovers from any panics and writes a 500 if there was one.
r.Use(mw2)
// Per route middleware, you can add as many as you desire.
r.GET("/benchmark", MyBenchLogger(), benchEndpoint)
}
For instance in above sniped is mw1 called first, or mw2 is? And is there a guarantee on their ordering?

They are executed in the order they are added to the router. That's why it is usually referred as middleware chain.
As you can see from the signature of functions that take middleware args, as Use, Group, etc. middlewares have type HandlerFunc and they are added to the HandlersChain, which is defined as:
type HandlersChain []HandlerFunc
So you can assume that context values set in a previous middleware will be available in the subsequent ones:
func main() {
r := gin.New()
r.Use(func(c *gin.Context) {
c.Set("key", "foo")
})
r.Use(func(c *gin.Context) {
fmt.Println(c.MustGet("key").(string)) // foo
})
}

Related

How does dgrouter handle middlewares?

I have a question regarding middlewares in various places:
I was reading about using middlewares with just stdlib to write request handlers as mentioned here: (https://www.alexedwards.net/blog/making-and-using-middleware)
func middlewareOne(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Our middleware logic goes here...
next.ServeHTTP(w, r)
})
}
mux := http.NewServeMux()
mux.Handle("/", middlewareOne(middlewareTwo(finalHandler)))
It makes sense to me that passing one handler inside another in this format executes the next middleware's ServeHTTP
I am using dgrouter for discord command routing and I found that I could use middlewares in there as well as defined in this example:
https://github.com/Necroforger/dgrouter/blob/master/examples/middleware/middleware.go#L40-L59
The method used to register middlewares is defined like so:
https://github.com/Necroforger/dgrouter/blob/master/exrouter/router_wrapper.go#L41-L49
My question is why is the middleware not called like how it is done in net/http and just the function name is passed:
router.Group(func(r *exrouter.Route) {
// Added routes inherit their parent category.
// I set the parent category here and it won't affect the
// Actual router, just this group
r.Cat("main")
// This authentication middleware applies only to this group
r.Use(Auth)
log.Printf("len(middleware) = %d\n", len(r.Middleware))
r.On("testauth", func(ctx *exrouter.Context) {
ctx.Reply("Hello " + ctx.Get("member").(*discordgo.Member).Nick + ", you have permission to use this command")
})
})
r.Use(Auth)
Is what i have difficulty understanding. Why is the function not being called?

Which ctx should I use in run parameter of hystrix.Do function of hystrix-go package? The ctx from upper level, or context.Background()?

Which ctx should I use in run parameter of hystrix.Do function of hystrix-go package? The ctx from the upper level, or context.Background()?
Thanks.
package main
import(
"context"
"github.com/myteksi/hystrix-go/hystrix"
)
func tb(ctx context.Context)error{
return nil
}
func ta(ctx context.Context){
hystrix.Do("cbName", func()error{
// At this place, the ctx parameter of function tb,
// Should I use ctx from ta function, or context.Background()?
return tb(ctx)
}, nil)
}
func main(){
ta(context.Background())
}
If you're using contexts, it seems to me like you should using hystrix.DoC. There's no reason to use anything than whatever context passed through, since Do is synchronous, and you would like whatever cancellations, deadlines (and whatever else is attached to your context) to be preserved inside this code.
func ta(ctx context.Context) {
err := hystrix.DoC(ctx, "cbName", func(ctx context.Context) error {
... code that uses ctx here.
}, nil)
// handle err, which may be a hystrix error.
}
It's hard to say if this is actually different from calling hystrix.Do, but this potentially allows hystrix to use your context, to add deadlines/cancellations itself.
Always use the context.Context coming from the upper level as a parameter wherever you can. It allows an end to end mechanism to control request, all the caller has to do is cancel, or invoke timeout on the initial ctx, and it will work for the complete request path.
The initial context passed can depend on your requirement. If you're not sure about what context to use initially, context.TODO can be a good option till you're sure.

How can I use the new context package from Go like I would use gorilla context library?

Go has come with a new package called context and with recent versions (Go 1.7 I think) we should be able to use it in the same way as gorilla/context package:
http://www.gorillatoolkit.org/pkg/context
With gorilla context you can very easily set and get variables that are relevant to a request, it's handlers, and middlewares.
To set a value in gorilla context is really easy:
func handleFunc(w http.ResponseWriter, r *http.Request) {
context.Set(r, "foo", "bar")
}
To get the value we can do:
func handleFunc(w http.ResponseWriter, r *http.Request) {
val := context.Get(r, "foo")
}
I understand that we can use this in middlewares so that the next middleware can use variables that were set in previous middleware. I would like to be able to do this with Go context package.
I understand that to get a value is quite simple like this:
func handleFunc(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.Context().Value("foo"))
}
But I have no idea how to set the value. It was not very intuitive for me and I don't really understand how to do it.
See "Exploring the context package", using WithValue and the context associated to the Request:
Middleware
Middleware in Go refers to an http handler which wraps around a multiplexer. There are several 3rd party middleware solutions (such as negroni), but really the standard library supports a very similar pattern. The use of a Context in the request allows us to hold data in the request.
See the example code for invocation and definition.
func putClientIPIntoContext(r *http.Request) context.Context {
ci := r.RemoteAddr
fwd := r.Header.Get("X-Forwarded-For")
if fwd != "" {
ci = fwd
}
ctx := context.WithValue(r.Context(), ClientIPKey, ci)
return ctx
}
The Context can store request-scoped variables.
It’s useful when writing ‘middleware’, but it’s a little bit ‘anti-pattern’ — it’s a bit magical, because it’s not type-safe.
See more at "Pitfalls of context values and how to avoid or mitigate them in Go".
The example below only shows how you might use the authentication logic from above to verify that when a user is logged in when visiting any page with a path prefix of /dashboard/.
A similar approach could be used to verify that a user is an admin before allowing them access to any page with a path prefix of /admin/.
func requireUser(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user := lookupUser(r)
if user == nil {
// No user so redirect to login
http.Redirect(w, r, "/login", http.StatusFound)
return
}
ctx := context.WithValue(r.Context(), "user", user)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func main() {
dashboard := http.NewServeMux()
dashboard.HandleFunc("/dashboard/hi", printHi)
dashboard.HandleFunc("/dashboard/bye", printBye)
mux := http.NewServeMux()
// ALL routes that start with /dashboard/ require that a
// user is authenticated using the requireUser middleware
mux.Handle("/dashboard/", requireUser(dashboard))
mux.HandleFunc("/", home)
http.ListenAndServe(":3000", addRequestID(mux))
}
As kostix comments, use Context wisely, like Dave Cheney suggest in "Context is for cancelation"

How to create a common function for all requests in Go?

I am writing a web application with Go to get better with it. My use case is pretty simple. I want to have a common function that will be executed for every request and will generate the navigation bar depending on the user status.
init method looks like (will also give you the idea of my implementation of handler methods):
func init() {
initDB()
gob.Register(user.User{})
r := mux.NewRouter()
r.HandleFunc("/", handleHome)
http.Handle("/", r)
}
I am using the following method to execute templates.
func executeTemplate(w http.ResponseWriter, name string, status int, data map[string]interface{}) error {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(status)
data["User"] = getUser(r)
return tpls[name].ExecuteTemplate(w, "base", data)
}
I am using Gorilla toolkit to store the session but as of my understanding, I need the http.Request instance every time to access the cookie store. Now I don't want to change the signature of executeTemplate method. Is there any way I can add a function to generate the navigation bar without changing signature of any of the existing methods?
What are some good ways to do it (even with changing the existing methods)?
Basic common approach to create middleware in Gorillatoolkit is to wrap top-level mux. Something like
func Middleware(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
//You do something here using request
h.ServeHTTP(w, r)
})
}
And then
r := mux.NewRouter()
r.HandleFunc("/", handleHome)
http.Handle("/", Middleware(r))

Go- authentication logic pattern in web app

I want to determine a simple and useful pattern for user authentication in a web app being written in golang.
I have come up with two patterns. First one is enabling the programmer to have his functions separate form the authentication logic, and has cleaner HandleFunc parts in main() that one can see only by loking main() to see what parts are under authentication control.
Second one is making programmer include a decision in every function deal with authentication required urls. An if statement checks by a authp() function defined else where.
Which one is better pattern for such necessity?
What are the better patterns for this job?
Is it even possible to pass a function to http.HandleFunc that has signature other than func urlFunc (ResponseWriter, *Request) bu like func urlFunc (successFunc, failFunc) or func urlFunc (ResponseWriter, *Request, successFunc, failFunc) as in authenticationGateKeeper function of First Way below, if not a suitable workaround for that?
//First Way
package main
func authGateKeeper(successFunc, failFunc) {
if (authp()) {
successFunc
} else {
failFunc
}
}
func authp() boolean {
//authentication logic, db query, or session check etc.
}
//usage in main
http.HandleFunc("/", authGateKeeper)
//Second Way; other alternative, in each function check pattern
func f(w, r) {
if (authp()) {
//function's processes
} else {
//the fail case function or processes
}
}
func authp() boolean {
//authentication logic, db query, or session check etc.
}
//usage in main
http.HandleFunc("/", f)
There are many ways to spin this, and it's arguable whether one is outright "better". I'd strongly suggest writing some middleware that wraps your routes and enforces the check, calling the wrapped handler only on success.
Note that I'm going to make a few assumptions here as you haven't told us how you're managing sessions (cookies? server-side?) and/or what kind of authorization you might need on top of authentication.
// Middleware - a function that sits in the 'middle' of your request processing.
func RequireAuth(h http.Handler) http.Handler) {
fn := func(w http.ResponseWriter, r *http.Request) {
// Assuming gorilla/sessions
session, err := store.Get("name", r)
if err != nil {
// Raise HTTP 500
return
}
// We'll assume you're storing the userID in the cookie|server session
// upon login elsewhere.
id := session.Values["userID"]
// Probably returns a *yourapp.User
user, err := db.GetUser(id)
if err != nil {
// Raise HTTP 500
return
}
if user == nil {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
// Don't forget these 'naked' returns - if you miss one, your
// handler will keep processing beyond the error and result in
// unintended side effects
return
}
// Further checks here - i.e. checking user.Active == true, etc.
// The userID matches one in the DB, so let's proceed
h.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
// And in your router - assuming just vanilla net/http
http.Handle("/", RequireAuth(yourHandlerFunc))
http.Handle("/", RequireAuth(someOtherHandler))
// Note that using gorilla/mux or goji can help give you "subrouters" so you
// don't have to wrap every single route with your middleware (messy, error prone)
I'd also suggest some reading on Go middleware1 composition2 which will help you in the future.
If you want to call a custom error page, just write a handler - e.g. UnauthorizedHandler that satisfies http.Handler and just call UnauthorizedHandler.ServeHTTP(w, r) instead of http.Error along the way.

Resources