From 346678027f1d517cfe2654b63a58d28c782568d5 Mon Sep 17 00:00:00 2001 From: Ruidy Date: Sat, 20 Sep 2025 00:50:40 +0200 Subject: [PATCH] feat: add chi middleware stack --- internal/server/handler_dashboard.go | 6 ++++-- internal/server/handler_public.go | 3 ++- internal/server/middleware.go | 30 ++++++++++++++++++++++++++++ internal/server/server.go | 8 ++++++++ internal/server/session.go | 23 +++++++++++---------- 5 files changed, 56 insertions(+), 14 deletions(-) create mode 100644 internal/server/middleware.go diff --git a/internal/server/handler_dashboard.go b/internal/server/handler_dashboard.go index ba538fa..167944b 100644 --- a/internal/server/handler_dashboard.go +++ b/internal/server/handler_dashboard.go @@ -4,12 +4,14 @@ import "net/http" func (s *Server) dashboardHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - if !s.sessions.IsAuthenticated() { + state := sessionFromContext(r.Context()) + + if !state.Authenticated { w.WriteHeader(http.StatusUnauthorized) s.render(w, "unauthorized.html", newUnauthorizedData("Sign in to continue.")) return } - s.render(w, "in.html", PageData{Email: s.sessions.CurrentAccount()}) + s.render(w, "in.html", PageData{Email: state.Email}) } } diff --git a/internal/server/handler_public.go b/internal/server/handler_public.go index 94688c9..7794f07 100644 --- a/internal/server/handler_public.go +++ b/internal/server/handler_public.go @@ -4,6 +4,7 @@ import "net/http" func (s *Server) indexHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - s.render(w, "index.html", newIndexData("", "")) + state := sessionFromContext(r.Context()) + s.render(w, "index.html", newIndexData(state.Email, "")) } } diff --git a/internal/server/middleware.go b/internal/server/middleware.go new file mode 100644 index 0000000..d68b90b --- /dev/null +++ b/internal/server/middleware.go @@ -0,0 +1,30 @@ +package server + +import ( + "context" + "net/http" +) + +func (s *Server) sessionMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + state := s.sessions.Snapshot() + ctx := withSession(r.Context(), state) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} + +type sessionContextKey struct{} + +func withSession(ctx context.Context, state SessionState) context.Context { + return context.WithValue(ctx, sessionContextKey{}, state) +} + +func sessionFromContext(ctx context.Context) SessionState { + if ctx == nil { + return SessionState{} + } + if state, ok := ctx.Value(sessionContextKey{}).(SessionState); ok { + return state + } + return SessionState{} +} diff --git a/internal/server/server.go b/internal/server/server.go index 7d343d9..14eec47 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -8,6 +8,7 @@ import ( "time" "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" "github.com/rjnemo/auth/internal/auth" "github.com/rjnemo/auth/web" @@ -52,6 +53,13 @@ func New() (*Server, error) { // Router returns the configured HTTP router. func (s *Server) Router() http.Handler { r := chi.NewRouter() + r.Use( + middleware.RequestID, + middleware.RealIP, + middleware.Logger, + middleware.Recoverer, + s.sessionMiddleware, + ) s.registerRoutes(r) return r } diff --git a/internal/server/session.go b/internal/server/session.go index 40cc4f0..8a7f569 100644 --- a/internal/server/session.go +++ b/internal/server/session.go @@ -2,6 +2,12 @@ package server import "sync" +// SessionState represents the snapshot of session metadata for a request. +type SessionState struct { + Authenticated bool + Email string +} + // SessionManager is a placeholder for future session persistence. type SessionManager struct { mu sync.RWMutex @@ -32,18 +38,13 @@ func (m *SessionManager) Clear() { m.currentAccount = "" } -// IsAuthenticated reports whether a user is currently considered logged in. -func (m *SessionManager) IsAuthenticated() bool { +// Snapshot captures the current session state for contextual use. +func (m *SessionManager) Snapshot() SessionState { m.mu.RLock() defer m.mu.RUnlock() - return m.authenticated -} - -// CurrentAccount returns the email associated with the active session. -func (m *SessionManager) CurrentAccount() string { - m.mu.RLock() - defer m.mu.RUnlock() - - return m.currentAccount + return SessionState{ + Authenticated: m.authenticated, + Email: m.currentAccount, + } }