package apiserver import ( "context" "log/slog" "net/http" "time" "gitea.perlbach24.de/scripte/nexarch/internal/auth" ) // authAndTenantContext prueft die Session (wiederverwendet auth.TokenIssuer.Verify // aus IAM-02 — keine zweite JWT-Implementierung) und setzt bei Erfolg // RequestContext fuer nachgelagerte Handler (Akzeptanzkriterium 3). Anders // als auth.RequireAuth (Klartext-Fehler) antwortet diese Middleware im // einheitlichen API-01-Fehlerschema (Akzeptanzkriterium 2), damit ALLE // Endpunkte unter /api/{version}/ dasselbe Format liefern, auch bei // Auth-Fehlern. func authAndTenantContext(issuer *auth.TokenIssuer, next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie(auth.CookieName) if err != nil { WriteError(w, http.StatusUnauthorized, "unauthenticated", "nicht angemeldet") return } claims, err := issuer.Verify(cookie.Value) if err != nil { WriteError(w, http.StatusUnauthorized, "unauthenticated", "nicht angemeldet") return } rc := RequestContext{UserID: claims.UserID, TenantSlug: claims.TenantSlug} next(w, r.WithContext(context.WithValue(r.Context(), requestContextKey, rc))) } } type statusRecorder struct { http.ResponseWriter status int } func (s *statusRecorder) WriteHeader(code int) { s.status = code s.ResponseWriter.WriteHeader(code) } // loggingMiddleware protokolliert jede Anfrage strukturiert. func loggingMiddleware(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { rec := &statusRecorder{ResponseWriter: w, status: http.StatusOK} start := time.Now() next(rec, r) slog.Info("api-anfrage", "method", r.Method, "path", r.URL.Path, "status", rec.status, "dauer", time.Since(start)) } }