feat(PROJ-1): httpOnly Cookie, Auditor-Guard, Nutzer-Aktionen (C)

Backend:
- Login setzt httpOnly SameSite=Strict Cookie (archivmail_session)
- Logout löscht Cookie + blacklistet Token
- authMiddleware: Cookie first, Bearer als Fallback (CLI kompatibel)

Frontend:
- api.ts: credentials: include statt localStorage/Bearer Token
- updateUser(), deleteUser() hinzugefügt
- useAuth: kein localStorage mehr, nur /api/auth/me
  requireRole: "admin" | "auditor" | undefined
- Login-Seite: kein localStorage
- Navbar: kein localStorage
- Admin: Nutzer-Aktionen (Sperren/Freischalten, Löschen, Passwort-Reset)
  Löschen verhindert wenn letzter Admin (HTTP 409)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sysops
2026-03-15 19:57:13 +01:00
co-authored by Claude Sonnet 4.6
parent a94b1d3e52
commit 7e165c8eed
6 changed files with 213 additions and 62 deletions
+5 -6
View File
@@ -16,10 +16,10 @@ export default function LoginPage() {
const [loading, setLoading] = useState(false);
useEffect(() => {
const token = localStorage.getItem("archivmail_token");
if (token) {
router.replace("/search");
}
// Check if already logged in via session cookie
import("@/lib/api").then(({ getMe }) =>
getMe().then(() => router.replace("/search")).catch(() => {})
);
}, [router]);
async function handleSubmit(e: React.FormEvent) {
@@ -28,8 +28,7 @@ export default function LoginPage() {
setLoading(true);
try {
const res = await login(username, password);
localStorage.setItem("archivmail_token", res.token);
await login(username, password);
router.push("/search");
} catch {
setError("Anmeldung fehlgeschlagen. Bitte Zugangsdaten pruefen.");