Documentation ¶
Overview ¶
The middleware package defines what a middleware is in trails and a set of basic middlewares.
The available middlewares are: - CORS - CurrentUser - ForceHTTPS - InjectSession - LogRequest - RateLimit - RequestID
Due to the amount of configuration required, middleware does not provide a default middleware chain Instead, the following can be copy-pasted:
vs := middleware.NewVisitors() adpts := []middleware.Adapter{ middleware.RateLimit(vs), middleware.ForceHTTPS(env), middleware.RequestID(requestIDKey), middleware.LogRequest(log), middleware.InjectSession(sessionStore, sessionKey), middleware.CurrentUser(responder, userStore, userKey), }
Index ¶
- Constants
- func Chain(handler http.Handler, adapters ...Adapter) http.Handler
- func GetIPAddress(hm http.Header) string
- func NoopAdapter(h http.Handler) http.Handler
- func ReportPanic(env string) func(http.HandlerFunc) http.HandlerFunc
- type Adapter
- func ApplyAuthorizer(d *resp.Responder, key ctx.CtxKeyable, fn UserAuthorizer) Adapter
- func CORS(base string) Adapter
- func CurrentUser(d *resp.Responder, store UserStorer, sessionKey, userKey ctx.CtxKeyable) Adapter
- func ForceHTTPS(env string) Adapter
- func InjectIPAddress() Adapter
- func InjectSession(store session.SessionStorer, key ctx.CtxKeyable) Adapter
- func LogRequest(ls logger.Logger) Adapter
- func RateLimit(visitors *Visitors) Adapter
- func RequestID(key ctx.CtxKeyable) Adapter
- func RequireAuthed(key ctx.CtxKeyable, loginUrl, logoffUrl string) Adapter
- func RequireUnauthed(key ctx.CtxKeyable) Adapter
- type User
- type UserAuthorizer
- type UserStorer
- type Visitor
- type Visitors
Constants ¶
const IpAddrCtxKey = "trails/middleware/ip-address" // TODO(dlk): change to key provided by app?
Variables ¶
This section is empty.
Functions ¶
func GetIPAddress ¶
GetIPAddress parses "X-Forward-For" and "X-Real-Ip" headers for the IP address from the request.
GetIPAddress skips addresses from non-public ranges.
func NoopAdapter ¶
NoopAdapter is a pass-through Adapter, often returned by Adapters available in this package when they are misconfigured.
func ReportPanic ¶
func ReportPanic(env string) func(http.HandlerFunc) http.HandlerFunc
ReportPanic encloses the env and returns a function that when called, wraps the passed in http.HandlerFunc in sentryhttp.HandleFunc in order to recover and report panics.
Types ¶
type Adapter ¶
An Adapter enables chaining middlewares together.
func ApplyAuthorizer ¶ added in v0.3.1
func ApplyAuthorizer(d *resp.Responder, key ctx.CtxKeyable, fn UserAuthorizer) Adapter
ApplyAuthorizer wraps a custom function validating the authorization of a User.
If that custom function returns false, ApplyAuthorizer responds to the request.
ApplyAuthorizer responds with http.StatusUnauthorized or a redirect to the URL provided by the custom function, depending on the "Accept" HTTP header of the request. If redirecting, a warning flash is added.
func CORS ¶
CORS sets "Access-Control-Allowed" style headers on a response. The handler including this middleware must also handle the http.MethodOptions method and not just the HTTP method it's designed for.
If base is it's zero-value, NoopAdapter returns and this middleware does nothing.
func CurrentUser ¶
func CurrentUser(d *resp.Responder, store UserStorer, sessionKey, userKey ctx.CtxKeyable) Adapter
CurrentUser pulls the User out of the session.UserSessionable stored in the *http.Request.Context.
A *resp.Responder is needed to handle cases a CurrentUser cannot be retrieved or does not have access.
CurrentUser checks the MIME types of the *http.Request "Accept" header in order to handle those cases. CurrentUser checks whether the "Accept" MIME type is "application/json" and write a status code if so. If it isn't, CurrentUser redirects to the Responder's root URL.
func ForceHTTPS ¶
ForceHTTPS redirects HTTP requests to HTTPS if the environment is not "development".
The "X-Forwarded-Proto" is used to check whether HTTP was requested due to a trails application running behind a proxy.
TODO(dlk): configurable headers to check.
func InjectIPAddress ¶
func InjectIPAddress() Adapter
InjectIPAddress grabs the IP address in the *http.Request.Header and promotes it to *http.Request.Context under IpAddrCtxKey.
func InjectSession ¶
func InjectSession(store session.SessionStorer, key ctx.CtxKeyable) Adapter
InjectSession stores the session associated with the *http.Request in *http.Request.Context.
If store or key are their zero-values, NoopAdapter returns and this middleware does nothing.
func LogRequest ¶
LogRequest logs the request's method, requested URL, and originating IP address using the enclosed implementation of logger.Logger.
LogRequest scrubs the values for the following keys: - password
if logger.Logger is nil, NoopAdapter returns and this middleware does nothing.
func RateLimit ¶
RateLimit encloses the Visitors map and serves the http.Handler
NOTE: cribbed from https://www.alexedwards.net/blog/how-to-rate-limit-http-requests
If we need anything more sophisticated, check https://github.com/didip/tollbooth
func RequestID ¶
func RequestID(key ctx.CtxKeyable) Adapter
RequestID adds a uuid to the request context.
If key is nil, then NoopAdapter returns and this middleware does nothing.
func RequireAuthed ¶ added in v0.3.2
func RequireAuthed(key ctx.CtxKeyable, loginUrl, logoffUrl string) Adapter
/ RequireAuthed returns a middleware.Adapter that checks whether a User is authenticated, and requires they be authenticated. When the User is authenticated, then RequireAuthed hands off to the next part of the middleware chain.
Authenticated means a User is set in the request context with the provided key.
When the User is not authenticated, and the request's "Accept" header has "application/json" in it, RequireUnauthed writes 401 to the client. If the request does not have that value in it's header, RequireAuthed redirects to the provided login URL.
The URL originally requested is appended to as a "next" query param when the request method is GET and the endpoint is not the logoff URL.
func RequireUnauthed ¶ added in v0.3.2
func RequireUnauthed(key ctx.CtxKeyable) Adapter
RequireUnauthed returns a middleware.Adapter that checks whether a user is authenticated and requires they not be authenticated. When they are not authenticated, RequireUnauthed hands off to the next part of the middleware chain.
Authenticated means a User is set in the request context with the provided key.
When the User is authenticated, and the request's "Accept" header has "application/json" in it, RequireUnauthed writes 400 to the client. If the request does not have that value in it's header, RequireUnauthed redirect to User's HomePath.
type UserAuthorizer ¶ added in v0.3.1
A UserAuthorizer checks some attribute the empty interface has.
Wrap a custom UserAuthorizer in ApplyAuthorizer to turn it into a middleware.
Presumably after casting to an app specific type, a UserAuthorizer returns false if the check was not met and an optional URL to be used in cases where a redirect ought to happen. Otherwise, a UserAuthorizer returns true.
type UserStorer ¶
UserStorer defines how to retrieve a User by an ID in the context of middleware.
type Visitors ¶
A Visitors maps a Visitor to an IP address.
func NewVisitors ¶
func NewVisitors() *Visitors