Dokumentation durchblättern
Module entwickeln
Berechtigungen & Rollen
Wie Schneespur Zugriffe steuert: granulare Berechtigungen, benannte Rollen und der Admin-Bypass — und wie ein Modul eigene Berechtigungen registriert und prüft.
Schneespur steuert Zugriffe über ein rollenbasiertes Berechtigungssystem. Ein Modul muss sich nicht um Login, Sitzungen oder Benutzerverwaltung kümmern — es meldet nur seine eigenen Berechtigungen an und prüft sie an den richtigen Stellen. Diese Seite zeigt, wie das zusammenhängt und warum die Trennung in Berechtigungen, Rollen und Benutzer sinnvoll ist.
Die drei Bausteine
Das System kennt drei Ebenen, die aufeinander aufbauen:
- Berechtigungen (Permissions) — granulare Einzelfähigkeiten, z. B.
customers.viewodersettings.edit. Eine Berechtigung beschreibt genau eine erlaubte Aktion. - Rollen (Roles) — benannte Sammlungen von Berechtigungen, z. B. „Admin” oder „Dispatcher”. Eine Rolle bündelt das, was eine Funktion im Betrieb tatsächlich tun darf.
- Benutzer (Users) — bekommen eine oder mehrere Rollen zugewiesen.
Der Vorteil dieser Aufteilung: Berechtigungen sind fein und stabil, Rollen sind das, was sich im Alltag ändert. Wer einem Mitarbeiter mehr Rechte geben will, ändert dessen Rolle — nicht jede einzelne Berechtigung von Hand.
Wie die Autorisierung abläuft
Der Weg von einer registrierten Berechtigung bis zur Prüfung im Controller verläuft über mehrere Stationen:
- Die
PermissionRegistryhält alle verfügbaren Berechtigungen (Core und Module). - Berechtigungen liegen in der Datenbanktabelle
permissions. - Rollen liegen in der Tabelle
roles, verknüpft über die Pivot-Tabellerole_permission. - Benutzer erhalten Rollen über die Pivot-Tabelle
role_user. - Das Trait
HasRolesamUser-Modell liefert Methoden wiehasPermission()undhasRole(). Gate::before()gewährt Admin-Benutzern bedingungslos alle Berechtigungen.
Weil die PermissionRegistry Core- und Modul-Berechtigungen gemeinsam hält, taucht eine
von Ihrem Modul registrierte Berechtigung an genau denselben Stellen auf wie eine
Core-Berechtigung — in der Rollenverwaltung, in den Prüfungen, überall.
Der Admin-Bypass
In AppServiceProvider::boot() hängt sich eine Prüfung vor alle anderen:
Gate::before(function ($user) {
if ($user->isAdmin()) {
return true; // Admins bypass all permission checks
}
});
Damit bestehen Admin-Benutzer jede Gate::allows()- und @can()-Prüfung automatisch.
Das ist bewusst so: Wenn Sie in Ihrem Modul eine neue Berechtigung einführen, müssen Sie Admins nicht gesondert berücksichtigen — sie haben ohnehin Zugriff. Sie prüfen einfach auf die fein gewählte Berechtigung, und der Bypass erledigt den Admin-Fall.
Modul-Berechtigungen registrieren
Eigene Berechtigungen meldet ein Modul über die PermissionRegistry an, typischerweise in
der boot()-Phase des ServiceProviders:
$permissions = app(PermissionRegistry::class);
$permissions->registerPermission(
slug: 'documents.view',
label: 'View documents',
group: 'documents',
module: 'documents', // identifies which module owns this permission
);
$permissions->registerPermission(
slug: 'documents.upload',
label: 'Upload documents',
group: 'documents',
module: 'documents',
);
$permissions->registerPermission(
slug: 'documents.delete',
label: 'Delete documents',
group: 'documents',
module: 'documents',
);
Der Parameter module hat einen praktischen Zweck: Er ordnet jede Berechtigung ihrem Modul
zu. Wird das Modul entfernt, räumt removeByModule() genau diese Berechtigungen wieder auf —
es bleiben keine verwaisten Einträge in der Tabelle permissions zurück.
Als Konvention bilden die Slugs das Muster gruppe.aktion ab (etwa documents.upload). Das
hält verwandte Berechtigungen in der Oberfläche beieinander und macht sie im Code lesbar.
Core-Berechtigungen
Diese Berechtigungen meldet die Anwendung selbst an. Sie stehen jedem Modul zur Prüfung zur
Verfügung — eine Navigation darf sich etwa an customers.view orientieren, ohne dass Ihr
Modul diese Berechtigung selbst definieren müsste:
| Gruppe | Slug | Bedeutung |
|---|---|---|
| dashboard | dashboard.view | Dashboard ansehen |
| customers | customers.view | Kunden ansehen |
| customers | customers.edit | Kunden bearbeiten |
| customers | customers.delete | Kunden löschen |
| drivers | drivers.view | Fahrer ansehen |
| drivers | drivers.edit | Fahrer bearbeiten |
| drivers | drivers.delete | Fahrer löschen |
| vehicles | vehicles.view | Fahrzeuge ansehen |
| vehicles | vehicles.edit | Fahrzeuge bearbeiten |
| vehicles | vehicles.delete | Fahrzeuge löschen |
| jobs | jobs.view | Aufträge ansehen |
| jobs | jobs.edit | Aufträge bearbeiten |
| jobs | jobs.delete | Aufträge löschen |
| workshifts | workshifts.view | Schichten ansehen |
| reports | reports.view | Berichte ansehen |
| alerts | alerts.view | Warnungen ansehen |
| alerts | alerts.resolve | Warnungen auflösen |
| settings | settings.view | Einstellungen ansehen |
| settings | settings.edit | Einstellungen bearbeiten |
| dsgvo | dsgvo.view | DSGVO-Informationen ansehen |
| dsgvo | dsgvo.edit | DSGVO-Einstellungen bearbeiten |
| gps | gps.view | GPS-Daten ansehen |
| help | help.view | Hilfe ansehen |
| users | users.view | Benutzer ansehen |
| users | users.edit | Benutzer bearbeiten |
| users | users.delete | Benutzer löschen |
| crontasks | crontasks.view | Cron-Aufgaben ansehen |
| crontasks | crontasks.manage | Cron-Aufgaben verwalten |
Rollen-Vorlagen
Rollen-Vorlagen sind vordefinierte Rollen-Konfigurationen, die ein Administrator beim Anlegen einer neuen Rolle als Ausgangspunkt übernehmen kann. So muss niemand eine sinnvolle Rechtekombination von Grund auf zusammenstellen — Ihr Modul kann eine passende Vorlage gleich mitliefern:
$templates = app(RoleTemplateRegistry::class);
$templates->registerTemplate(
slug: 'accountant',
name: 'Buchhaltung',
description: 'Zugriff auf Dokumente, Berichte und Exporte',
permissions: [
'dashboard.view',
'documents.view',
'reports.view',
'customers.view',
],
module: 'documents',
);
Eine Vorlage ist ein Vorschlag, keine feste Rolle: Der Administrator entscheidet, ob und wie
er sie anwendet. Auch hier ordnet module die Vorlage Ihrem Modul zu.
Berechtigungen im Modul prüfen
Geprüft wird dort, wo eine Aktion ausgeführt oder eine Schaltfläche angezeigt wird. Drei Stellen sind typisch.
Im Controller
use Illuminate\Support\Facades\Gate;
public function index()
{
Gate::authorize('documents.view');
// ... render the view
}
Gate::authorize() bricht mit einem Berechtigungsfehler ab, wenn der Benutzer die
Berechtigung nicht hat — die einfachste Absicherung am Einstiegspunkt einer Aktion.
In Blade-Views
@can('documents.upload')
<button>Upload Document</button>
@endcan
So wird eine Schaltfläche nur den Benutzern angezeigt, die sie auch nutzen dürfen. Das ersetzt aber nicht die Prüfung im Controller: Sichtbarkeit allein ist keine Absicherung — die eigentliche Aktion gehört trotzdem geschützt.
Im Code
if ($user->hasPermission('documents.view')) {
// User has the permission through one of their roles
}
if ($user->hasRole('admin')) {
// User has the admin role
}
hasPermission() prüft die Berechtigung über alle Rollen des Benutzers hinweg.
Das HasRoles-Trait
Das User-Modell nutzt das Trait HasRoles, das diese Methoden bereitstellt:
$user->roles(); // BelongsToMany relationship
$user->hasRole('admin'): bool; // check role by slug
$user->assignRole('dispatcher'); // add role (slug or Role model)
$user->removeRole('dispatcher'); // remove role
$user->hasPermission('jobs.view'): bool; // check permission via any role
$user->loadPermissions(): array; // get all permission slugs (cached)
$user->flushPermissionCache(): void; // clear in-memory cache
Die Berechtigungen eines Benutzers werden im Speicher zwischengehalten (loadPermissions()
liefert die zwischengespeicherte Liste). Wenn Sie Rollen oder Rechte zur Laufzeit ändern,
leert flushPermissionCache() diesen Zwischenspeicher, damit die nächste Prüfung den neuen
Stand sieht.
Benutzer-Rollen (Enum)
Das Enum UserRole definiert die Basis-Rollentypen:
enum UserRole: string {
case Admin = 'admin';
case Driver = 'driver';
}
Dazu bietet das User-Modell zwei Bequemlichkeitsmethoden:
$user->isAdmin(): bool;
$user->isDriver(): bool;
isAdmin() ist genau die Methode, auf die sich der weiter oben beschriebene Admin-Bypass
stützt.
Berechtigungen in Navigation und Widgets
Sowohl die NavigationRegistry als auch die DashboardWidgetRegistry verstehen
berechtigungsabhängige Sichtbarkeit. So zeigt die Oberfläche jedem Benutzer nur das, was zu
seinen Rechten passt:
// Only users with 'documents.view' see this nav item
$nav->addItem(
group: 'stammdaten',
slug: 'documents',
label: 'Dokumente',
route: 'admin.documents.index',
icon: 'heroicon-o-document',
permission: 'documents.view',
);
// Only users with 'documents.view' see this widget
$widgets->registerWidget('recent-documents', [
'view' => 'documents::widgets.recent',
'permission' => 'documents.view',
]);
Das ist dieselbe Idee wie @can in der View, nur eine Ebene höher: Ein Menüpunkt oder
Widget verschwindet für alle, denen die nötige Berechtigung fehlt. Auch hier gilt — die
verlinkte Aktion selbst muss im Controller geschützt bleiben.
Wie ein Modul Berechtigungen, Rollen-Vorlagen und alle weiteren Registries im ServiceProvider anmeldet, zeigt das ServiceProvider-Muster. Die vollständige API der hier genannten Registries finden Sie unter Registries.