add user.FromContext middleware
A helper package so that handler and render code isnt directly tied to the authentication package. Also reduces db lookup overhead to one request to sqlite per request for the user lookup.
This commit is contained in:
parent
3c58a1361c
commit
91dd6017e0
|
@ -50,6 +50,12 @@ func (h invitesH) create(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
user := user.FromContext(req.Context())
|
||||
if user == nil {
|
||||
err := fmt.Errorf("warning: no user session for elevated access request")
|
||||
h.r.Error(w, req, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
aliasSuggestion := req.Form.Get("alias_suggestion")
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
roomsAuth "github.com/ssb-ngi-pointer/go-ssb-room/web/handlers/auth"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/web/i18n"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/web/router"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/web/user"
|
||||
)
|
||||
|
||||
var HTMLTemplates = []string{
|
||||
|
@ -108,27 +109,7 @@ func New(
|
|||
return u
|
||||
}
|
||||
}),
|
||||
render.InjectTemplateFunc("is_logged_in", func(r *http.Request) interface{} {
|
||||
no := func() *admindb.User { return nil }
|
||||
|
||||
v, err := a.AuthenticateRequest(r)
|
||||
if err != nil {
|
||||
return no
|
||||
}
|
||||
|
||||
uid, ok := v.(int64)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("warning: not the expected ID type from authenticated session: %T\n", v))
|
||||
}
|
||||
|
||||
user, err := fs.GetByID(r.Context(), uid)
|
||||
if err != nil {
|
||||
return no
|
||||
}
|
||||
|
||||
yes := func() *admindb.User { return user }
|
||||
return yes
|
||||
}),
|
||||
render.InjectTemplateFunc("is_logged_in", user.TemplateHelper()),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("web Handler: failed to create renderer: %w", err)
|
||||
|
@ -259,16 +240,23 @@ func New(
|
|||
|
||||
mainMux.Handle("/", m)
|
||||
|
||||
// apply middleware
|
||||
var finalHandler http.Handler = mainMux
|
||||
finalHandler = logging.InjectHandler(logger)(finalHandler)
|
||||
finalHandler = CSRF(finalHandler)
|
||||
|
||||
if web.Production {
|
||||
return finalHandler, nil
|
||||
// apply HTTP middleware
|
||||
middlewares := []func(http.Handler) http.Handler{
|
||||
logging.InjectHandler(logger),
|
||||
user.ContextInjecter(fs, a),
|
||||
CSRF,
|
||||
}
|
||||
|
||||
return r.GetReloader()(finalHandler), nil
|
||||
if !web.Production {
|
||||
middlewares = append(middlewares, r.GetReloader())
|
||||
}
|
||||
|
||||
var finalHandler http.Handler = mainMux
|
||||
for _, mw := range middlewares {
|
||||
finalHandler = mw(finalHandler)
|
||||
}
|
||||
|
||||
return finalHandler, nil
|
||||
}
|
||||
|
||||
// utils
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
// Package user implements helpers for accessing the currently logged in admin or moderator of an active request.
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/admindb"
|
||||
"go.mindeco.de/http/auth"
|
||||
)
|
||||
|
||||
type roomUserContextKeyType string
|
||||
|
||||
var roomUserContextKey roomUserContextKeyType = "ssb:room:httpcontext:user"
|
||||
|
||||
// FromContext returns the user or nil of it's not logged in
|
||||
func FromContext(ctx context.Context) *admindb.User {
|
||||
v := ctx.Value(roomUserContextKey)
|
||||
|
||||
user, ok := v.(*admindb.User)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
// ContextInjecter returns the middleware that injects the user value into the request context
|
||||
func ContextInjecter(fs admindb.AuthFallbackService, a *auth.Handler) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
|
||||
v, err := a.AuthenticateRequest(req)
|
||||
if err != nil {
|
||||
next.ServeHTTP(w, req)
|
||||
return
|
||||
}
|
||||
|
||||
uid, ok := v.(int64)
|
||||
if !ok {
|
||||
next.ServeHTTP(w, req)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := fs.GetByID(req.Context(), uid)
|
||||
if err != nil {
|
||||
next.ServeHTTP(w, req)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(req.Context(), roomUserContextKey, user)
|
||||
next.ServeHTTP(w, req.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TemplateHelper returns a function to be used with the http/render package.
|
||||
// It has to return a function twice because the first is evaluated with the request before it gets passed onto html/template's FuncMap.
|
||||
func TemplateHelper() func(*http.Request) interface{} {
|
||||
return func(r *http.Request) interface{} {
|
||||
no := func() *admindb.User { return nil }
|
||||
|
||||
user := FromContext(r.Context())
|
||||
if user == nil {
|
||||
return no
|
||||
}
|
||||
|
||||
yes := func() *admindb.User { return user }
|
||||
return yes
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue