feat: Registrierung, Anmeldung und Sitzungen
Passwörter mit bcrypt, Sitzungen als opake Token in der Datenbank — im Cookie steht das Klartext-Token, in der Tabelle nur dessen SHA-256. Damit lassen sich einzelne Geräte gezielt abmelden, was reine JWT-Sitzungen nicht hergeben. Der erste registrierte Zugang wird automatisch Administrator, sonst käme man nach dem Aufsetzen nicht in die Verwaltung. Die Registrierung ist instanzweit abschaltbar; solange es keinen Nutzer gibt, bleibt sie offen. Enthält außerdem API-Schlüssel je Nutzer als Grundlage für die spätere REST-API und die Instanz-Einstellungen in der Tabelle AppSetting.
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import type { Metadata } from "next";
|
||||
import { getSessionUser } from "@/lib/auth";
|
||||
import { getSettings, isRegistrationOpen } from "@/lib/settings";
|
||||
import { env } from "@/lib/env";
|
||||
import { AuthSwitch, LoginForm } from "@/components/AuthForm";
|
||||
import { loginAction } from "../actions";
|
||||
|
||||
export const metadata: Metadata = { title: "Anmelden" };
|
||||
|
||||
export default async function LoginPage({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: Promise<{ weiter?: string; fehler?: string }>;
|
||||
}) {
|
||||
if (await getSessionUser()) redirect("/");
|
||||
|
||||
const params = await searchParams;
|
||||
const [settings, registrationOpen] = await Promise.all([getSettings(), isRegistrationOpen()]);
|
||||
|
||||
return (
|
||||
<div className="fl-card p-6 sm:p-8">
|
||||
<h1 className="text-2xl font-semibold tracking-tight">Willkommen zurück</h1>
|
||||
<p className="mt-1 mb-6 text-sm text-[var(--fl-muted)]">
|
||||
Melde dich an, um weiterzuschauen.
|
||||
</p>
|
||||
|
||||
{params.fehler && (
|
||||
<p
|
||||
role="alert"
|
||||
className="mb-4 rounded-xl border border-[color-mix(in_oklab,var(--fl-danger)_45%,transparent)] bg-[color-mix(in_oklab,var(--fl-danger)_12%,transparent)] px-3 py-2 text-sm text-[var(--fl-danger)]"
|
||||
>
|
||||
{params.fehler}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<LoginForm action={loginAction} weiter={params.weiter} />
|
||||
|
||||
{env.oidc.isConfigured && (
|
||||
<>
|
||||
<div className="my-5 flex items-center gap-3 text-xs text-[var(--fl-faint)]">
|
||||
<span className="h-px flex-1 bg-[var(--fl-border)]" />
|
||||
oder
|
||||
<span className="h-px flex-1 bg-[var(--fl-border)]" />
|
||||
</div>
|
||||
<a href="/api/auth/oidc/start" className="fl-btn fl-btn-ghost w-full">
|
||||
{env.oidc.buttonLabel}
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
|
||||
{registrationOpen && (
|
||||
<div className="mt-6">
|
||||
<AuthSwitch href="/registrieren">Noch kein Konto? Jetzt registrieren</AuthSwitch>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p className="mt-6 text-center text-xs text-[var(--fl-faint)]">{settings.instanceName}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user