There are several ways to archive your goal.
Solution 1:
Implement a "func IsAuthenticated(r *http.Request) bool" method and use it like this in your handlers:
func handleFoo(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
http.Redirect(w, r, "/login", http.StatusSeeOther)
return
}
// process the request
}
Solution 2:
Implement a "AuthOnly" middleware. Something like this:
type AuthHandler struct {
h http.Handler
}
func (a AuthHandler) ServeHttp(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
http.Redirect(w, r, "/login", http.StatusSeeOther)
return
}
h.ServeHttp(w, r)
}
func AuthOnly(h http.Handler) http.Handler {
return AuthHandler{h}
}
Usage example:
http.Handle("/login", loginHandler)
http.Handle("/admin", AuthOnly(adminHandler))
// etc.
Solution 3:
Use your own handler signature. For example:
type Context struct {
req http.Request
currentUser string
// and a lot more App specific things
}
type HandleFunc func (w http.ResponseWriter, ctx *Context) error
func (h HandleFunc) ServeHttp(w http.ResponseWriter, r *http.Request) {
ctx := &Context{req: r, currentUser: "anonymous"}
err := h(w, ctx)
if err != nil {
http.Error(w, err.String(), http.StatusInternalServerError)
return
}
}
And now, you can implement your own handlers:
func handleAdmin(w http.ResponseWriter, ctx *Context) error {
// todo
}
http.Handle("/admin", HandleFunc(handleAdmin))
Solution 4:
Stay with the http.Handler interface, but generate a Context object if you need one. This approach is used by the AppEngine for Go library.
Example:
type Context struct {
req *http.Request
currentUser string
// and a lot more App specific things
}
func NewContext(r *http.Request) *Context {
return &Context{req: r}
}
type (ctx *Context) IsAuthenticated() bool {
// todo
}
func handleAdmin(w http.ResponseWriter, r *http.Request) {
ctx := NewContext(r)
if !ctx.IsAuthenticated() {
// ...
}
}
I haven't tested any code in this post, so the samples might include a lot of minor mistakes, but I hope you got the general approach. According to your first post, solution 1 should be sufficient, but solution 2 might be a nice addition. Solution 3 and 4 is only useful in bigger projects I think. Solution 3 has the advantage that you can also change the handler interface so that you can return error's directly, but those Handlers need your custom middleware to be compatible with the http package. Which solution is suited best for you depends heavily on your project. So pick the appropriate one yourself.
-christoph