Berechtigungsbewusste Navigationsmenüs verbessern die Übersicht, müssen aber im Backend durchgesetzt werden. Einfache Muster für Rollen, Policies und sicheres UI-Ausblenden.

Wenn Leute sagen „versteck den Button“, meinen sie meist eins von zwei Dingen: Unordnung für Nutzer:innen reduzieren, die eine Funktion nicht nutzen können, oder Missbrauch verhindern. Nur das erste Ziel ist auf der Oberfläche realistisch.
Berechtigungsbewusste Navigationsmenüs sind vor allem ein UX-Werkzeug. Sie helfen Nutzer:innen, die App zu öffnen und sofort zu sehen, was sie tun können, ohne bei jedem zweiten Klick auf "Zugriff verweigert" zu stoßen. Sie senken außerdem den Supportaufwand, weil Verwirrung wie „Wo genehmige ich Rechnungen?“ oder „Warum zeigt diese Seite einen Fehler?“ entfällt.
UI ausblenden ist keine Sicherheit. Es ist Klarheit.
Selbst ein neugieriger Kollege kann dennoch:
Das eigentliche Problem, das berechtigungsbewusste Menüs lösen, ist ehrliche Orientierung. Sie halten die Oberfläche im Einklang mit Aufgabe, Rolle und Kontext des Nutzers, und machen gleichzeitig deutlich, wenn etwas nicht verfügbar ist.
Ein gutes Endergebnis sieht so aus:
Beispiel: In einem kleinen CRM sollte ein Sales-Rep Leads und Tasks sehen, aber nicht User Management. Wenn er trotzdem die User-Management-URL einfügt, muss die Seite geschlossen fehlschlagen, und der Server muss es blockieren, Nutzer aufzulisten oder Rollen zu ändern.
Sichtbarkeit ist, was die Oberfläche zeigt. Autorisierung ist, was das System tatsächlich erlaubt, wenn eine Anfrage den Server erreicht.
Berechtigungsbewusste Menüs reduzieren Verwirrung. Wenn jemand nie Zugriff auf Billing oder Admin haben wird, hält das Ausblenden dieser Elemente die App sauber und senkt Support-Tickets. Aber das Verstecken eines Buttons ist kein Schloss. Menschen können trotzdem versuchen, das zugrunde liegende Endpoint über Dev-Tools, alte Lesezeichen oder kopierte Requests zu erreichen.
Eine praktische Regel: Entscheide, welches Erlebnis du wollst, und setze die Regel im Backend durch, egal was die UI tut.
Wenn du entscheidest, wie eine Aktion präsentiert wird, decken drei Muster die meisten Fälle ab:
„Du kannst ansehen, aber nicht bearbeiten“ ist häufig und lohnt, explizit entworfen zu werden. Behandle es als zwei Berechtigungen: eine fürs Lesen, eine fürs Ändern. Im Menü zeigst du vielleicht Kundendetails allen, die lesen dürfen, aber „Kunde bearbeiten" nur denen mit Schreibzugriff. Auf der Seite rendere Felder schreibgeschützt und sperre Edit-Kontrollen, während die Seite trotzdem lädt.
Wichtig: Das Backend entscheidet das finale Ergebnis. Selbst wenn die UI alle Admin-Aktionen ausblendet, muss der Server bei jeder sensiblen Anfrage die Berechtigung prüfen und eine klare „nicht erlaubt"-Antwort zurückgeben, wenn jemand es versucht.
Der schnellste Weg, berechtigungsbewusste Menüs zu liefern, ist mit einem Modell zu starten, das dein Team in einem Satz erklären kann. Wenn du es nicht erklären kannst, wirst du es nicht korrekt halten.
Nutze Rollen zum Gruppieren, nicht als Bedeutungsquelle. Admin und Support sind nützliche Buckets. Aber wenn Rollen zu sehr multiplizieren (Admin-West-Coast-ReadOnly), wird die UI zum Labyrinth und das Backend zum Ratespiel.
Bevorzuge Berechtigungen als Quelle der Wahrheit dafür, was jemand tun kann. Halte sie klein und aktionsbasiert, wie invoice.create oder customer.export. Das skaliert besser als Rollen-Explosion, weil neue Features meist neue Aktionen hinzufügen, nicht neue Jobtitel.
Dann füge Policies (Regeln) für Kontext hinzu. Hier behandelst du „kann nur eigenen Datensatz bearbeiten“ oder „kann Rechnungen nur bis $5.000 genehmigen“. Policies verhindern, dass du Dutzende fast identischer Berechtigungen erstellst, die sich nur in einer Bedingung unterscheiden.
Eine wartbare Schichtung sieht so aus:
Naming ist wichtiger, als viele erwarten. Wenn deine UI „Export Customers“ sagt, die API aber download_all_clients_v2 verwendet, wirst du irgendwann das Falsche ausblenden oder das Richtige blockieren. Halte Namen menschlich, konsistent und sowohl Frontend als auch Backend gemeinsam:
noun.verb (oder resource.action)Beispiel: In einem CRM könnte die Sales-Rolle lead.create und lead.update enthalten, aber eine Policy beschränkt Updates auf Leads, die der Nutzer besitzt. So bleibt dein Menü klar, während das Backend strikt bleibt.
Berechtigungsbewusste Menüs fühlen sich gut an, weil sie Unordnung reduzieren und versehentliche Klicks verhindern. Aber sie helfen nur, wenn das Backend die Kontrolle behält. Denk an die UI als Hinweis, den Server als Richter.
Beginne damit aufzuschreiben, was du schützt. Nicht Seiten, sondern Aktionen. Kundenliste ansehen ist etwas anderes als Kunden exportieren oder Kunden löschen. Das ist das Rückgrat von Menüs, die nicht zur Sicherheits-Show werden.
canEditCustomers, canDeleteCustomers, canExport oder eine kompakte Liste von Berechtigungs-Strings zurück. Halte es minimal.Eine kleine, aber wichtige Regel: Vertraue niemals rollen- oder berechtigungsbezogenen Flags, die der Client sendet. Die UI kann Buttons ausblenden basierend auf Capabilities, aber die API muss dennoch unautorisierte Anfragen ablehnen.
Berechtigungsbewusste Menüs sollten Menschen helfen, zu finden, was sie tun können, nicht so tun, als würden sie Sicherheit erzwingen. Das Frontend ist eine Leitplanke. Das Backend ist das Schloss.
Statt Berechtigungsprüfungen in jeden Button zu streuen, definiere deine Navigation aus einer Konfiguration, die die benötigte Berechtigung für jedes Element enthält, und rendere daraus. Das hält Regeln lesbar und verhindert vergessene Prüfungen in Ecken der UI.
Ein einfaches Muster sieht so aus:
const menu = [
{ label: "Contacts", path: "/contacts", requires: "contacts.read" },
{ label: "Export", action: "contacts.export", requires: "contacts.export" },
{ label: "Admin", path: "/admin", requires: "admin.access" },
];
const visibleMenu = menu.filter(item => userPerms.includes(item.requires));
Ziehe es vor, ganze Bereiche (wie Admin) auszublenden, statt überall Checks auf jeden einzelnen Admin-Link zu streuen. Das sind weniger Stellen, an denen etwas schiefgehen kann.
Blende Elemente aus, wenn der Nutzer nie berechtigt sein wird, sie zu nutzen. Deaktiviere Elemente, wenn der Nutzer die Berechtigung hat, aber der aktuelle Kontext fehlt.
Beispiel: „Kontakt löschen" sollte deaktiviert sein, bis ein Kontakt ausgewählt ist. Gleiche Berechtigung, nur nicht genug Kontext. Wenn du deaktivierst, füge eine kurze „Warum"-Nachricht nahe der Kontrolle hinzu (Tooltip, Hilfetext oder Inline-Hinweis): Kontakt auswählen, um zu löschen.
Ein Regelwerk, das bestand hat:
Menüeinträge auszublenden hilft Menschen, sich zu fokussieren, aber schützt nichts. Das Backend muss die endgültige Instanz sein, weil Anfragen wiederholt, editiert oder außerhalb deiner UI ausgelöst werden können.
Eine gute Regel: Jede Aktion, die Daten ändert, braucht eine Autorisierungsprüfung an einer Stelle, die jede Anfrage passiert. Das kann Middleware, ein Handler-Wrapper oder eine kleine Policy-Schicht sein, die du zu Beginn jedes Endpunkts aufrufst. Wähle einen Ansatz und bleib dabei, sonst verpasst du Pfade.
Halte Autorisierung getrennt von Input-Validation. Entscheide zuerst: „Darf dieser Nutzer das?", dann validiere die Nutzlast. Wenn du zuerst validierst, kannst du Details (z. B. ob eine ID existiert) an jemanden leaken, der die Aktion gar nicht wissen dürfte.
Ein Muster, das skaliert:
Can(user, "invoice.delete", invoice)).Verwende Statuscodes, die sowohl deinem Frontend als auch deinen Logs helfen:
401 Unauthorized, wenn der Aufrufer nicht eingeloggt ist.403 Forbidden, wenn eingeloggt, aber nicht berechtigt.Sei vorsichtig mit 404 Not Found als Tarnung. Es kann nützlich sein, um zu vermeiden, dass eine Ressource existiert, aber wenn du es wild mischt, wird Debugging schwierig. Wähle eine konsistente Regel pro Ressourcentyp.
Stelle sicher, dass dieselbe Autorisierung läuft, egal ob die Aktion aus einem Button-Klick, einer mobilen App, einem Script oder einem direkten API-Aufruf kam.
Logge abgelehnte Versuche für Debugging und Audits, aber schütze die Logs. Zeichne auf: wer, welche Aktion, welcher grobe Ressourcentyp. Vermeide sensitive Felder, volle Payloads oder Geheimnisse.
Die meisten Berechtigungsfehler zeigen sich, wenn Nutzer:innen etwas tun, das dein Menü nie erwartet hat. Deshalb sind berechtigungsbewusste Menüs nützlich, aber nur, wenn du auch Pfade berücksichtigst, die daran vorbeiführen.
Wenn das Menü Billing für eine Rolle ausblendet, kann ein Nutzer trotzdem eine gespeicherte URL einfügen oder sie aus dem Browserverlauf öffnen. Behandle jeden Seitenaufruf wie eine frische Anfrage: Lade die aktuellen Berechtigungen des Nutzers und lass den Screen geschützte Daten verweigern, wenn die Berechtigung fehlt. Eine freundliche Meldung „Du hast keinen Zugriff" ist in Ordnung, aber der echte Schutz ist, dass das Backend nichts zurückgibt.
Jede:r kann deine API aus Dev-Tools, einem Script oder einem anderen Client anrufen. Prüfe also Berechtigungen an jedem Endpunkt, nicht nur an Admin-Screens. Das leicht zu übersehende Risiko sind Bulk-Aktionen: Ein einziger /items/bulk-update kann unbeabsichtigt einem Nicht-Admin erlauben, Felder zu ändern, die er in der UI nie sieht.
Rollen können sich auch mitten in einer Session ändern. Wenn ein Admin eine Berechtigung entfernt, hat der Benutzer vielleicht noch ein altes Token oder ein gecachtes Menü. Verwende kurzlebige Tokens oder eine serverseitige Berechtigungsabfrage und handhabe 401/403-Antworten, indem du Berechtigungen neu lädst und die UI aktualisierst.
Geteilte Geräte sind eine weitere Falle: Ein gecachter Menüzustand kann zwischen Accounts leaken. Speichere Menüsichtbarkeit nach User-ID oder vermeide es, sie zu persistieren.
Fünf Tests, die vor dem Release Sinn machen:
Stell dir ein internes CRM mit drei Rollen vor: Sales, Support und Admin. Alle melden sich an und die App zeigt ein links stehendes Menü, aber das Menü ist nur Komfort. Die echte Sicherheit bestimmt der Server.
Hier ein simples Berechtigungsset, das lesbar bleibt:
Die UI fragt das Backend nach den erlaubten Aktionen des aktuellen Nutzers (oft als Liste von Berechtigungs-Strings) plus Basis-Kontext wie Nutzer-ID und Team. Das Menü baut sich daraus. Wenn du billing.view nicht hast, siehst du Billing nicht. Wenn du leads.export hast, siehst du auf der Leads-Seite einen Export-Button. Wenn du nur eigene Leads bearbeiten kannst, kann der Edit-Button trotzdem erscheinen, sollte aber deaktiviert sein oder eine klare Meldung zeigen, wenn der Lead nicht dir gehört.
Wichtig: Jeder Action-Endpunkt erzwingt dieselben Regeln.
Beispiel: Sales kann Leads erstellen und Leads bearbeiten, die ihnen gehören. Support kann Tickets ansehen und zuweisen, aber nicht Billing anfassen. Admin kann Nutzer und Billing verwalten.
Wenn jemand versucht, einen Lead zu löschen, prüft das Backend:
leads.delete?lead.owner_id == user.id?Selbst wenn ein Support-Nutzer manuell das Delete-Endpoint aufruft, bekommt er eine Forbidden-Antwort. Das ausgeblendete Menüelement war nie der Schutz. Die Backend-Entscheidung war es.
Die größte Falle ist zu denken, die Arbeit sei erledigt, wenn das Menü richtig aussieht. Buttons auszublenden reduziert Verwirrung, aber nicht das Risiko.
Häufige Fehler:
isAdmin-Flag für alles. Es fühlt sich schnell an, dann verbreitet es sich. Bald wird jede Ausnahme ein Spezialfall und niemand kann Zugriffsregeln erklären.role, isAdmin oder permissions aus dem Browser als Wahrheit. Leite Identität und Zugriff aus deiner eigenen Session oder Token ab und schlage Rollen/Berechtigungen serverseitig nach.Konkretes Beispiel: Du blendest den Export-Leads-Menüpunkt für Nicht-Manager aus. Wenn der Export-Endpunkt die Berechtigung nicht prüft, kann jeder, der die Anfrage errät (oder sie von einem Kollegen kopiert), die Datei herunterladen.
Bevor du berechtigungsbewusste Menüs ausrollst, mach eine letzte Runde fokussiert auf das, was Nutzer tatsächlich tun können, nicht nur darauf, was sie sehen.
Gehe deine App als jede Hauptrolle durch und versuche dieselben Aktionen. Mach das in der UI und rufe auch direkt die Endpunkte (oder Dev-Tools) auf, um sicherzustellen, dass der Server die Quelle der Wahrheit ist.
Checkliste:
Eine praktische Methode, Lücken zu finden: Wähle einen „gefährlichen" Button (Nutzer löschen, CSV exportieren, Billing ändern) und verfolge ihn Ende-zu-Ende. Das Menüelement sollte passend ausgeblendet sein, die API unautorisierte Calls ablehnen und die UI sollte sich bei einem 403 sauber erholen.
Fang klein an. Am ersten Tag brauchst du keine perfekte Zugriffsmatrix. Wähle die Handvoll Aktionen, die am wichtigsten sind (view, create, edit, delete, export, manage users), mappe sie auf vorhandene Rollen und mach weiter. Wenn ein neues Feature kommt, füge nur die neuen Aktionen hinzu, die es einführt.
Bevor du Bildschirme baust, mache einen kurzen Planungs-Pass, der Aktionen auflistet, nicht Seiten. Ein Menüpunkt wie Invoices verbirgt viele Aktionen: Liste anzeigen, Details ansehen, erstellen, refund, export. Das Aufschreiben macht UI und Backend-Regeln klarer und verhindert, dass du eine Seite sperrst, während ein riskanter Endpoint ungeschützt bleibt.
Wenn du Zugriffsregeln refaktorierst, behandle es wie jede riskante Änderung: leg ein Sicherheitsnetz an. Snapshots lassen dich Verhalten vorher/nachher vergleichen. Wenn eine Rolle plötzlich notwendigen Zugriff verliert oder unerwartet Zugriff gewinnt, ist Zurückrollen schneller als Hotfix in Produktion, während Nutzer blockiert sind.
Eine einfache Release-Routine hilft Teams, schnell zu bleiben ohne zu raten:
Wenn du mit einer chatbasierten Plattform wie Koder.ai (koder.ai) baust, gilt dasselbe Prinzip: Definiere Berechtigungen und Policies einmal, lass die UI Capabilities vom Server lesen und mache Backend-Prüfungen in jedem Handler obligatorisch.
Berechtigungsbewusste Menüs lösen vor allem Klarheit, nicht Sicherheit. Sie helfen Nutzer:innen, sich auf das zu konzentrieren, was sie tatsächlich tun können, reduzieren Sackgassen-Klicks und senken Supportanfragen wie „Warum sehe ich das?“ oder „Wo genehmige ich Rechnungen?".
Sicherheit muss weiterhin im Backend durchgesetzt werden, weil jede:r tiefe Links, alte Lesezeichen oder direkte API-Aufrufe versuchen kann – unabhängig davon, was die UI anzeigt.
Ausblenden, wenn eine Funktion für eine Rolle praktisch unerkennbar sein soll und kein erwarteter Weg existiert, sie zu nutzen.
Deaktivieren, wenn die Nutzer:in grundsätzlich Zugriff haben könnte, aber gerade Kontext fehlt – z. B. kein Eintrag ausgewählt, Formular ungültig oder Daten werden noch geladen. Wenn du deaktivierst, füge eine kurze Erklärung hinzu, damit es nicht kaputt wirkt.
Weil Sichtbarkeit nicht gleich Autorisierung ist. Nutzer:innen können eine URL einfügen, ein gespeichertes Admin-Panel wiederverwenden oder deine API außerhalb der UI ansprechen.
Behandle die UI als Wegweiser. Behandle das Backend als endgültige Entscheidungsinstanz für jede sensible Anfrage.
Dein Server sollte nach dem Login oder bei Session-Refresh eine kleine „Capabilities“-Antwort zurückgeben, basierend auf serverseitigen Prüfungen. Die UI rendert Menüs und Buttons aus diesen Fähigkeiten.
Vertraue nicht auf klientenseitig übermittelte Flags wie isAdmin; berechne Berechtigungen aus der authentifizierten Identität auf dem Server.
Beginne mit einer Inventarisierung von Aktionen, nicht Seiten. Separiere z. B. lesen, erstellen, aktualisieren, löschen, exportieren, einladen und Rechnungsänderungen.
Durchsetze jede Aktion im Backend-Handler (oder Middleware/Wrapper), bevor Arbeit ausgeführt wird. Verbinde das Menü mit denselben Berechtigungsnamen, damit UI und API übereinstimmen.
Praktisch: Rollen sind Buckets, Berechtigungen sind die Quelle der Wahrheit. Halte Berechtigungen klein und aktionsbasiert (z. B. invoice.create) und weise sie Rollen zu.
Wenn Rollen anfangen zu multiplizieren, um Bedingungen auszudrücken (Region, ReadOnly etc.), verlagere Bedingungen in Policies statt neue Rollen zu erfinden.
Nutze Policies für kontextuelle Regeln wie „nur eigene Datensätze bearbeiten“ oder „Rechnungen nur bis zu einem Betrag genehmigen“. So bleibt die Berechtigungsliste stabil, während reale Einschränkungen abgebildet werden.
Das Backend bewertet die Policy anhand des Ressourcen-Kontexts (Owner-ID, Org-ID), nicht anhand von Annahmen aus der UI.
Nicht immer. Aber sensitive Reads oder Endpunkte, die normales Filtern umgehen, sollten geprüft werden – z. B. Exporte, Audit-Logs, Gehaltsdaten oder Admin-Listen.
Eine gute Faustregel: Alle Schreibaktionen müssen geprüft werden, und sensitive Lesefunktionen ebenfalls.
Bulk-Endpunkte sind leicht zu übersehen, da sie viele Datensätze oder Felder in einer Anfrage ändern können. Prüfe sowohl die Berechtigung für die Bulk-Aktion selbst als auch, welche Felder für die Rolle erlaubt sind zu ändern. Sonst kannst du versehentlich versteckte Felder änderbar machen.
Gehe davon aus, dass Berechtigungen sich während einer Sitzung ändern können. Wenn die API 401 oder 403 zurückgibt, sollte die UI das normal behandeln: Fähigkeiten neu laden, Menü aktualisieren und eine klare Meldung zeigen.
Vermeide außerdem, Menüzustand so zu speichern, dass er sich über Konten hinweg auf gemeinsamen Geräten austauscht; wenn du cachest, dann pro Nutzer-ID oder gar nicht.