package auth import ( "encoding/json" "net/http" "time" ) // Handler stellt Login/Logout als HTTP-Endpunkte bereit. Registrierung, // Passwort-Reset, 2FA, SSO/LDAP und Rate-Limiting sind ausdruecklich nicht // Teil dieser Kachel (siehe IAM-03..07). type Handler struct { login *LoginService } func NewHandler(login *LoginService) *Handler { return &Handler{login: login} } type loginRequest struct { Email string `json:"email"` Password string `json:"password"` } func (h *Handler) Login(w http.ResponseWriter, r *http.Request) { var req loginRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "ungueltige Anfrage", http.StatusBadRequest) return } token, err := h.login.Login(r.Context(), req.Email, req.Password) if err != nil { http.Error(w, ErrInvalidCredentials.Error(), http.StatusUnauthorized) return } http.SetCookie(w, &http.Cookie{ Name: CookieName, Value: token, Path: "/", HttpOnly: true, Secure: true, SameSite: http.SameSiteStrictMode, MaxAge: int(AccessTokenTTL.Seconds()), }) w.WriteHeader(http.StatusOK) } // Logout loescht das Session-Cookie. Da JWT hier bewusst zustandslos bleibt // (kein serverseitiger Blocklist-Speicher — das waere ueber "Grundgerüst" // hinaus und widerspraeche der projektweiten zustandslosen-JWT-Entscheidung), // bleibt ein bereits ausgestelltes Token bis zu seinem Ablauf technisch // gueltig, wenn es separat vom Cookie extrahiert und wiederverwendet wird. func (h *Handler) Logout(w http.ResponseWriter, r *http.Request) { http.SetCookie(w, &http.Cookie{ Name: CookieName, Value: "", Path: "/", HttpOnly: true, Secure: true, SameSite: http.SameSiteStrictMode, MaxAge: -1, Expires: time.Unix(0, 0), }) w.WriteHeader(http.StatusOK) }