gorilla / mux

Package gorilla/mux is a powerful HTTP router and URL matcher for building Go web servers with 🦍

Home Page:https://gorilla.github.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[FEATURE] Route metadata

deborggraever opened this issue · comments

Is there an existing feature request for this?

  • I have searched the existing feature requests

Is your feature request related to a problem? Please describe.

Currently it is difficult to do authorization on routes based on claim requirements, unless we do the check inside the http handler.
Coming from a C# .NET world, there it is easy because it support attributes like an [Authorize] attribute.

As workaround i added a unique name to each route, and created a authorization mapping between the route name and the authorization policy.

Middleware

var routePolicies map[string]string
var authPolicies map[string]authorization.Policy

func authMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		route := mux.CurrentRoute(r)
		policyName, ok := routePolicies[route.GetName()]
		if !ok {
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}

		policy, ok := authPolicies[policyName]
		if !ok || !policy.MeetsRequirements(r.Context()) {
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}

		next.ServeHTTP(w, r)
	})
}

Setup

// Register the route
r.HandleFunc("/v1/product", api.GetProductsHandlerV1).Methods(http.MethodGet).Name("product_api:GetProductsHandlerV1")
r.HandleFunc("/v1/product/{id}", api.GetProductByIdHandlerV1).Methods(http.MethodGet).Name("product_api:GetProductByIdHandlerV1")

// Set the route policies
routePolicies["product_api:GetProductsHandlerV1"] = "product.read"
routePolicies["product_api:GetProductByIdHandlerV1"] = "product.read"

// Create the policies
authPolicies["product.read"] = authorization.NewPolicy(
    "product.read",
    NewUserRequirement(),
    NewScopeRequirement("product.read"),
)

Describe the solution that you would like.

To make it easy to create an authorization middleware with limited code, it would be nice to have metadata on a route.

Example:

r.HandleFunc("/v1/product", api.GetProductsHandlerV1).Methods(http.MethodGet).Metadata("authPolicy", "product.read")
r.HandleFunc("/v1/product/{id}", api.GetProductByIdHandlerV1).Methods(http.MethodGet).Metadata("authPolicy", "product.read")

func authMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		route := mux.CurrentRoute(r)
		policy, ok := authPolicies[route.GetMetadata()["authPolicy"]]
		if !ok || !policy.MeetsRequirements(r.Context()) {
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}

		next.ServeHTTP(w, r)
	})
}

Route metadata could be used for many other solutions, where u want to set some properties on a route to use inside the handler or middlewares

Describe alternatives you have considered.

No response

Anything else?

No response