Alle PlaybooksNext.js + Supabase

Eine geschützte Seite hinzufügen

Eine Seite nur für angemeldete Nutzer oder Admins hinzufügen, mit der Prüfung auf dem Server und den Daten hinter RLS.

Wann du es brauchst

Eine neue Seite, die nur angemeldete Nutzer oder nur Admins öffnen dürfen: ein Kontobereich, ein Dashboard, Einstellungen.

Regeln

  • src/proxy.ts aktualisiert die Sitzung und leitet zu /login weiter, damit die Navigation flüssiger ist. Das ist nicht die Zugriffskontrolle: Die Seite prüft den Nutzer selbst, und die Daten sind durch RLS geschützt.
  • Identität und Rolle werden auf dem Server ermittelt. Die Rolle kommt aus profiles (member oder admin); lies sie nie aus Query-String, Cookie oder Formularfeld.
  • Seiten, die Nutzerdaten lesen, sind Server Components. Nutze eine Client Component nur für die interaktiven Teile und gib ihr die Daten als Props.

Schritte

  1. Lege src/app/<route>/page.tsx als asynchrone Server Component an und beginne wie in src/app/page.tsx:

    import { redirect } from "next/navigation";
    import { createClient } from "@/lib/supabase/server";
    
    export default async function AccountPage() {
      const supabase = await createClient();
      const { data: { user } } = await supabase.auth.getUser();
      if (!user) redirect("/login");
      // ...
    }
    

    Nutze getUser(), das die Sitzung bei Supabase prüft, nicht getSession(), das nur das Cookie liest.

  2. Lies bei einer Admin-Seite die Rolle nach der Nutzerprüfung und brich mit notFound() ab, damit die Seite ihre Existenz nicht verrät:

    const { data: profile } = await supabase
      .from("profiles")
      .select("role")
      .eq("id", user.id)
      .single();
    if (profile?.role !== "admin") notFound();
    
  3. Prüfe den Proxy. In dieser Foundation leitet updateSession (src/lib/supabase/middleware.ts) ohne Sitzung jeden Pfad außer /login, /register und /auth zu /login weiter, eine neue Seite ist also bereits abgedeckt. Wenn die Datei eine Liste geschützter Präfixe definiert, wie die Produkte auf dieser Foundation, füge dort das neue Präfix hinzu.

  4. Lade Daten mit demselben supabase-Client: Abfragen laufen als der Nutzer und RLS greift. Braucht die Seite eine neue Tabelle, folge zuerst dem Playbook „Eine Tabelle mit RLS hinzufügen“.

  5. Änderungen laufen über eine Server Action oder einen Route Handler, der die Prüfung mit getUser() wiederholt, bei Admin-Aktionen auch die Rolle: Sie lassen sich aufrufen, ohne die Seite zu öffnen.

  6. Verlinke die Seite in der Navigation nur für Nutzer, die sie öffnen dürfen. Öffnet sie einen neuen Bereich des Produkts, beschreibe ihn in ARCHITECTURE.md.

Fertig, wenn

  • die Prüfbefehle erfolgreich sind;
  • die Seite ohne Sitzung zu /login weiterleitet;
  • bei einer Admin-Seite ein member-Konto eine 404 erhält;
  • jede Server Action und jeder Route Handler der Seite den Nutzer erneut prüft.