How to apply middleware

243 views
Skip to first unread message

afriyie...@gmail.com

unread,
Apr 3, 2019, 10:35:19 AM4/3/19
to golang-nuts
Hi,

I have this main function in a main.go file inside the main directory
func main() {
    log.Printf("Server started")

    router := sw.NewRouter()
    manager := manage.NewDefaultManager()
    manager.SetAuthorizeCodeTokenCfg(manage.DefaultAuthorizeCodeTokenCfg)

    manager.MustTokenStorage(store.NewMemoryTokenStore())

    clientStore := store.NewClientStore()
    manager.MapClientStorage(clientStore)

    srv := server.NewDefaultServer(manager)
    srv.SetAllowGetAccessRequest(true)
    srv.SetClientInfoHandler(server.ClientFormHandler)
    manager.SetRefreshTokenCfg(manage.DefaultRefreshTokenCfg)

    srv.SetInternalErrorHandler(func(err error) (re *errors.Response) {
        log.Println("Internal Error:", err.Error())
        return
    })

    srv.SetResponseErrorHandler(func(re *errors.Response) {
        log.Println("Response Error:", re.Error.Error())
    })

    router.HandleFunc("/oauth2/token", func(w http.ResponseWriter, r *http.Request) {
        srv.HandleTokenRequest(w, r)
    })

    router.HandleFunc("/credentials", func(w http.ResponseWriter, r *http.Request) {
        clientId := uuid.New().String()[:8]
        clientSecret := uuid.New().String()[:8]
        err := clientStore.Set(clientId, &models.Client{
            ID:     clientId,
            Secret: clientSecret,
            Domain: "http://localhost:9094",
        })
        if err != nil {
            fmt.Println(err.Error())
        }

        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(map[string]string{"CLIENT_ID": clientId, "CLIENT_SECRET": clientSecret})
    })

    log.Fatal(http.ListenAndServe(":8000", router))
}


The functions below are in different files in the sub directory of the main as

*maindir
    *subdir


//Funtion in handler.go in subdir

func protecteduri(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello, I'm protected"))
}

//This function in middleware.go in subdir

func validateToken(f http.HandlerFunc, srv *server.Server) http.HandlerFunc {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        _, err := srv.ValidationBearerToken(r)
        if err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }

        f.ServeHTTP(w, r)
    })
}

And my routes are in the router.go in the subdir as

type Route struct {
    Name        string
    Method      string
    Pattern     string
    HandlerFunc http.HandlerFunc
}

type Routes []Route

func NewRouter() *mux.Router {
    router := mux.NewRouter().StrictSlash(true)
    for _, route := range routes {
        var handler http.Handler
        handler = route.HandlerFunc
        handler = Logger(handler, route.Name)

        router.
            Methods(route.Method).
            Path(route.Pattern).
            Name(route.Name).
            Handler(handler)
    }

    return router
}

func Index(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World!")
}

var routes = Routes{
    {
        "Index",
        "GET",
        "/",
        Index,
    },

    {
        "protecteduri",
        strings.ToUpper("Get"),
        "/protected",
        protecteduri,
    },
}

My question is how do i apply the "validateToken" function (middleware) to the routes in the router.go?
The function is to validate the access token in the request message before calling the handler functions.









Burak Serdar

unread,
Apr 3, 2019, 11:47:12 AM4/3/19
to afriyie...@gmail.com, golang-nuts
Have you looked at the gorilla/mux documentation about middlewares?
There are examples there: https://godoc.org/github.com/gorilla/mux

You need to change the validateToken func:

func getTokenMW(srv *server.Server) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
}
}
}

Then:
router.Use(getTokenMW(server))

Or, you can define a struct, put the server pointer in it, and use a
member function of that struct as the middleware.

afriyie...@gmail.com

unread,
Apr 4, 2019, 3:46:08 AM4/4/19
to golang-nuts
changing and using "router.Use(getTokenMW(server))" is validating all the routes. How can i exclude routes
/oauth2/token and /credentials. I read that populate but i dont get the idea. 
Any clew about how to go about this?

afriyie...@gmail.com

unread,
Apr 4, 2019, 4:44:14 AM4/4/19
to golang-nuts
I have modify the middleware to the below but it only work if the handler function "/protected" is in the main function.
I have many handlers and do not want to put all of them in the main.go. 
You suggest i define a struct and use member function of the struct, can you elaborate more about for me or the format.

func ValidateToken(srv *server.Server) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
notAuth := []string{"/oauth2/token", "/credentials"} //List of endpoints that doesn't require auth
requestPath := r.URL.Path                            //current request path

//check if request does not need authentication, serve the request if it doesn't need it
for _, value := range notAuth {

if value == requestPath {
next.ServeHTTP(w, r)
return
}
}
_, err := srv.ValidationBearerToken(r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

next.ServeHTTP(w, r)
})
}
}

car...@hotmail.com

unread,
Apr 4, 2019, 12:54:27 PM4/4/19
to golang-nuts
How about something like this?  Unsure about concurrent access to global variables, but if you want to access srv and clientstore from package sw, It'd make sense to me to move srv and clientstore out of main and into a package.

howToApplyMiddleware
main.go
- server
server.go
- sw
handler.go
router.go
middleware.go

//main.go
package main

import (
"log"
"net/http"
"howToApplyMiddleware/sw"
)

func main() {
log.Printf("Server started")
log.Fatal(http.ListenAndServe(":8000", sw.Router))
}


//server.go
package server

import (
"log"
)

var ClientStore *store.ClientStore
var SRV *server.Server

func init() {
ClientStore = store.NewClientStore()
manager := manage.NewDefaultManager()
manager.SetAuthorizeCodeTokenCfg(manage.DefaultAuthorizeCodeTokenCfg)
manager.MapClientStorage(ClientStore)
manager.SetRefreshTokenCfg(manage.DefaultRefreshTokenCfg)
manager.MustTokenStorage(store.NewMemoryTokenStore())

SRV = server.NewDefaultServer(manager)
SRV.SetAllowGetAccessRequest(true)
SRV.SetClientInfoHandler(server.ClientFormHandler)

SRV.SetInternalErrorHandler(func(err error) (re *errors.Response) {
log.Println("Internal Error:", err.Error())
return
})

SRV.SetResponseErrorHandler(func(re *errors.Response) {
log.Println("Response Error:", re.Error.Error())
})
}


//handler.go
package sw

import (
"net/http"
)

//Funtion in handler.go in subdir

func protecteduri(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, I'm protected"))
}


//middleware.go
package sw

import (
"net/http"
"howToApplyMiddleware/server"
)

//This function in middleware.go in subdir

func validateToken(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
_, err := server.SRV.ValidationBearerToken(r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
f(w, r)

}
}


//router.go
package sw

import (
"encoding/json"
"fmt"
"net/http"
"howToApplyMiddleware/server"
"strings"
)

var Router *mux.Router

func init() {
Router = NewRouter()
Router.HandleFunc("/oauth2/token", func(w http.ResponseWriter, r *http.Request) {
server.SRV.HandleTokenRequest(w, r)
})

Router.HandleFunc("/credentials", func(w http.ResponseWriter, r *http.Request) {
clientId := uuid.New().String()[:8]
clientSecret := uuid.New().String()[:8]
err := server.ClientStore.Set(clientId, &models.Client{
ID:     clientId,
Secret: clientSecret,
})
if err != nil {
fmt.Println(err.Error())
}

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"CLIENT_ID": clientId, "CLIENT_SECRET": clientSecret})
})
}

type Route struct {
Name        string
Method      string
Pattern     string
HandlerFunc http.HandlerFunc
}

type Routes []Route

func NewRouter() *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
var handler http.Handler
handler = route.HandlerFunc
//handler = Logger(handler, route.Name)

router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(handler)
}

return router
}

func Index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
}

var routes = Routes{
{
"Index",
"GET",
"/",
Index,
},

{
"protecteduri",
strings.ToUpper("Get"),
"/protected",
validateToken(protecteduri),
},

Burak Serdar

unread,
Apr 4, 2019, 1:03:30 PM4/4/19
to afriyie...@gmail.com, golang-nuts
On Thu, Apr 4, 2019 at 1:46 AM <afriyie...@gmail.com> wrote:
>
> changing and using "router.Use(getTokenMW(server))" is validating all the routes. How can i exclude routes
> /oauth2/token and /credentials. I read that populate but i dont get the idea.
> Any clew about how to go about this?

You can use subrouters:

sub:=router.PathPrefix("/protected").Subrouter()
sub.Use(...)
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Burak Serdar

unread,
Apr 4, 2019, 1:07:13 PM4/4/19
to afriyie...@gmail.com, golang-nuts
On Thu, Apr 4, 2019 at 2:44 AM <afriyie...@gmail.com> wrote:
>
> I have modify the middleware to the below but it only work if the handler function "/protected" is in the main function.
> I have many handlers and do not want to put all of them in the main.go.
> You suggest i define a struct and use member function of the struct, can you elaborate more about for me or the format.

Something like this:

type TokenHandler struct {
Server *server.Server
}

func (t TokenHandler) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(...)
}

In main:

tokenMW:=TokenHandler{Server:srv}
router.Use(tokenMW.Middleware)

You can define the middlewares in any package you want, they don't
have to be in main.

afriyie...@gmail.com

unread,
Apr 5, 2019, 3:36:31 AM4/5/19
to golang-nuts
Hi,

Yes this make sense and it works. The code also look simple to read.
Thanks!!
Reply all
Reply to author
Forward
0 new messages