Optimize CurrentUser to read from DB only once per request

This commit is contained in:
Noah 2022-08-21 14:17:52 -07:00
parent 748adeb289
commit 967e149875
3 changed files with 24 additions and 7 deletions

View File

@ -1,6 +1,7 @@
package middleware
import (
"context"
"net/http"
"time"
@ -46,7 +47,9 @@ func LoginRequired(handler http.Handler) http.Handler {
}
}
handler.ServeHTTP(w, r)
// Stick the CurrentUser in the request context so future calls to session.CurrentUser can read it.
ctx := context.WithValue(r.Context(), session.CurrentUserKey, user)
handler.ServeHTTP(w, r.WithContext(ctx))
})
}
@ -55,19 +58,26 @@ func AdminRequired(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// User must be logged in.
if currentUser, err := session.CurrentUser(r); err != nil {
currentUser, err := session.CurrentUser(r)
if err != nil {
log.Error("AdminRequired: %s", err)
errhandler := templates.MakeErrorPage("Login Required", "You must be signed in to view this page.", http.StatusForbidden)
errhandler.ServeHTTP(w, r)
return
} else if !currentUser.IsAdmin {
}
// Stick the CurrentUser in the request context so future calls to session.CurrentUser can read it.
ctx := context.WithValue(r.Context(), session.CurrentUserKey, currentUser)
// Admin required.
if !currentUser.IsAdmin {
log.Error("AdminRequired: %s", err)
errhandler := templates.MakeErrorPage("Admin Required", "You do not have permission for this page.", http.StatusForbidden)
errhandler.ServeHTTP(w, r)
errhandler.ServeHTTP(w, r.WithContext(ctx))
return
}
handler.ServeHTTP(w, r)
handler.ServeHTTP(w, r.WithContext(ctx))
})
}

View File

@ -11,6 +11,12 @@ import (
func CurrentUser(r *http.Request) (*models.User, error) {
sess := Get(r)
if sess.LoggedIn {
// Did we already get the CurrentUser once before?
ctx := r.Context()
if user, ok := ctx.Value(CurrentUserKey).(*models.User); ok {
return user, nil
}
// Load the associated user ID.
return models.GetUser(sess.UserID)
}

View File

@ -26,8 +26,9 @@ type Session struct {
}
const (
ContextKey = "session"
CSRFKey = "csrf"
ContextKey = "session"
CurrentUserKey = "current_user"
CSRFKey = "csrf"
)
// New creates a blank session object.