Unterschied zwischen Authentifizierung und Autorisierung
Authentifizierung stellt fest, „wer” ein Benutzer ist. Der Login-Vorgang ist das klassische Beispiel.
Autorisierung entscheidet, „was” dieser Benutzer tun darf. Etwa: dass Benutzer nur ihre eigenen Beiträge bearbeiten dürfen oder dass Einstellungen nur von Administratoren geändert werden können.Nachdem Sie mit der Authentifizierung die Anmeldung implementiert haben, folgt als nächster Schritt die Autorisierung.
Für die Autorisierung bietet Laravel zwei Ansätze: Gates und Policies. Welchen Sie einsetzen, hängt vom Anwendungsfall ab.
Entscheidungshilfe
Szenario
Empfehlung
Einfache Prüfung ohne Bezug auf ein bestimmtes Model
Gate
Berechtigungen für CRUD-Operationen an einem Model
Policy
Zugriffssteuerung für ein Admin-Dashboard
Gate
Berechtigungen für das Erstellen, Bearbeiten und Löschen von Blogbeiträgen
Ein Gate ist eine schlanke, auf Closures basierende Autorisierungsprüfung. Es eignet sich für Berechtigungsentscheidungen, die nicht an ein bestimmtes Model gebunden sind.
Gates werden mit Gate::define() in der Methode boot von App\Providers\AppServiceProvider definiert.
// app/Providers/AppServiceProvider.phpuse App\Models\Post;use App\Models\User;use Illuminate\Support\Facades\Gate;public function boot(): void{ Gate::define('update-post', function (User $user, Post $post) { return $user->id === $post->user_id; });}
Die Closure eines Gates erhält als ersten Parameter stets den aktuell authentifizierten Benutzer. Weitere Parameter können zusätzliche Informationen wie das zu prüfende Model enthalten.
Um bei fehlender Berechtigung automatisch eine 403-Antwort zu senden, verwenden Sie Gate::authorize(). Damit sparen Sie sich den manuellen Aufruf von abort(403).
public function update(Request $request, Post $post): RedirectResponse{ Gate::authorize('update-post', $post); // Nur bei ausreichender Berechtigung erreicht die Ausführung diesen Punkt // Beitrag aktualisieren ... return redirect('/posts');}
Gate::authorize() wirft bei fehlender Berechtigung eine Illuminate\Auth\Access\AuthorizationException. Laravel wandelt diese automatisch in eine HTTP-403-Antwort um.
Wenn Administratoren alle Berechtigungen erhalten sollen, verwenden Sie Gate::before().
use App\Models\User;use Illuminate\Support\Facades\Gate;public function boot(): void{ // $ability enthält den Namen des aufgerufenen Gates (z. B. 'update-post') Gate::before(function (User $user, string $ability) { if ($user->isAdministrator()) { return true; } }); Gate::define('update-post', function (User $user, Post $post) { return $user->id === $post->user_id; });}
Wenn die Closure in before einen Wert ungleich null zurückgibt, ist dieses Ergebnis die endgültige Entscheidung. Bei null (oder keiner Rückgabe) läuft die reguläre Gate-Prüfung weiter.
In Templates sind die Direktiven @can und @cannot für Gate-Prüfungen praktisch.
@can('update-post', $post) <a href="{{ route('posts.edit', $post) }}">Bearbeiten</a>@endcan@cannot('update-post', $post) <p>Sie haben keine Berechtigung, diesen Beitrag zu bearbeiten.</p>@endcannot
Eine Policy bündelt die Autorisierungslogik zu einem bestimmten Model in einer eigenen Klasse. Für Berechtigungen zum Anlegen, Anzeigen, Bearbeiten und Löschen eines Post-Models eignen sich Policies besser als Gates.
Laravel erkennt Policies standardmäßig anhand einer Namenskonvention automatisch.
Model: app/Models/Post.php
Policy: app/Policies/PostPolicy.php
Wenn Sie diese Konvention einhalten, entfällt das explizite Registrieren der Policy.
Wenn Sie die Konvention nicht einhalten oder die Policy manuell registrieren möchten, verwenden Sie Gate::policy() in der boot-Methode des AppServiceProvider.
use App\Models\Post;use App\Policies\PostPolicy;use Illuminate\Support\Facades\Gate;Gate::policy(Post::class, PostPolicy::class);
In Laravel 13 können Sie die Zuordnung auch deklarativ über das Attribut #[UsePolicy] am Model festlegen.
use App\Policies\PostPolicy;use Illuminate\Database\Eloquent\Attributes\UsePolicy;#[UsePolicy(PostPolicy::class)]class Post extends Model {}
Eine mit --model erzeugte Policy enthält Methoden, die den üblichen CRUD-Aktionen entsprechen.
<?phpnamespace App\Policies;use App\Models\Post;use App\Models\User;class PostPolicy{ /** * Darf der Benutzer die Beitragsübersicht ansehen? */ public function viewAny(User $user): bool { return true; // Jeder authentifizierte Benutzer darf die Übersicht sehen } /** * Darf der Benutzer einen bestimmten Beitrag ansehen? */ public function view(User $user, Post $post): bool { return true; // Jeder authentifizierte Benutzer darf den Beitrag sehen } /** * Darf der Benutzer einen Beitrag erstellen? */ public function create(User $user): bool { return true; // Jeder authentifizierte Benutzer darf posten } /** * Darf der Benutzer einen Beitrag bearbeiten? */ public function update(User $user, Post $post): bool { return $user->id === $post->user_id; // Nur eigene Beiträge dürfen bearbeitet werden } /** * Darf der Benutzer einen Beitrag löschen? */ public function delete(User $user, Post $post): bool { return $user->id === $post->user_id; // Nur eigene Beiträge dürfen gelöscht werden }}
Auch in einer Policy können Sie mit einer before-Methode Administratoren pauschal alle Berechtigungen erteilen.
/** * Vorabprüfung, die vor allen anderen Policy-Methoden ausgeführt wird. * $ability enthält den Namen der Policy-Methode (z. B. 'update' oder 'delete'). */public function before(User $user, string $ability): bool|null{ if ($user->isAdministrator()) { return true; // Administratoren dürfen alles } return null; // Rückgabe null → Ausführung der regulären Policy-Methode}
Die before-Methode wird nur aufgerufen, wenn in der Policy-Klasse eine passende Methode existiert. Fehlt zum Beispiel die Methode update, wird auch before nicht aufgerufen.
Der Basis-Controller von Laravel stellt die Hilfsmethode authorize() bereit (wenn Sie nicht vom Basis-Controller erben, verwenden Sie Gate::authorize()).
Gate::authorize()
User::can() / cannot()
<?phpnamespace App\Http\Controllers;use App\Models\Post;use Illuminate\Http\RedirectResponse;use Illuminate\Http\Request;use Illuminate\Support\Facades\Gate;class PostController extends Controller{ public function update(Request $request, Post $post): RedirectResponse { Gate::authorize('update', $post); // Beitrag aktualisieren ... return redirect()->route('posts.index'); } public function store(Request $request): RedirectResponse { Gate::authorize('create', Post::class); // Beitrag erstellen ... return redirect()->route('posts.index'); } public function destroy(Post $post): RedirectResponse { Gate::authorize('delete', $post); $post->delete(); return redirect()->route('posts.index'); }}
<?phpnamespace App\Http\Controllers;use App\Models\Post;use Illuminate\Http\RedirectResponse;use Illuminate\Http\Request;class PostController extends Controller{ public function update(Request $request, Post $post): RedirectResponse { if ($request->user()->cannot('update', $post)) { abort(403); } // Beitrag aktualisieren ... return redirect()->route('posts.index'); }}
RESTful-Policies gesammelt mit authorizeResource() registrieren
Rufen Sie im Konstruktor authorizeResource() auf, um für jede Aktion eines Controllers automatisch die passende Policy-Methode zu verknüpfen.
<?phpnamespace App\Http\Controllers;use App\Models\Post;class PostController extends Controller{ public function __construct() { $this->authorizeResource(Post::class, 'post'); } // Für index(), show(), create(), store(), edit(), update() und destroy() // wird automatisch die passende Policy-Methode angewendet}
Zuordnung zwischen Controller-Aktionen und Policy-Methoden:
Controller-Aktion
Policy-Methode
index
viewAny
show
view
create / store
create
edit / update
update
destroy
delete
Mit authorizeResource() müssen Sie nicht in jeder Aktion einzeln authorize() aufrufen. In Kombination mit einem RESTful-Resource-Controller ist das besonders praktisch.
Um Autorisierungsprüfungen auf Routen-Ebene durchzuführen, verwenden Sie die Middleware can.
use App\Models\Post;// Nur Benutzer mit Berechtigung zum Aktualisieren von BeiträgenRoute::put('/posts/{post}', [PostController::class, 'update']) ->middleware('can:update,post');// Nur Benutzer mit Berechtigung zum Erstellen von BeiträgenRoute::post('/posts', [PostController::class, 'store']) ->middleware('can:create,App\Models\Post');
Beispiel für eine Blog-Anwendung, in der „nur der Autor eines Beitrags ihn bearbeiten und löschen darf”.
1
Policy erzeugen
php artisan make:policy PostPolicy --model=Post
2
Policy-Methoden implementieren
<?phpnamespace App\Policies;use App\Models\Post;use App\Models\User;class PostPolicy{ /** * Administratoren alle Berechtigungen erteilen */ public function before(User $user, string $ability): bool|null { if ($user->is_admin) { return true; } return null; } public function viewAny(User $user): bool { return true; } public function view(User $user, Post $post): bool { return true; } public function create(User $user): bool { return true; } public function update(User $user, Post $post): bool { return $user->id === $post->user_id; } public function delete(User $user, Post $post): bool { return $user->id === $post->user_id; }}
3
authorizeResource() im Controller hinzufügen
<?phpnamespace App\Http\Controllers;use App\Models\Post;use Illuminate\Http\RedirectResponse;use Illuminate\Http\Request;use Illuminate\View\View;class PostController extends Controller{ public function __construct() { $this->authorizeResource(Post::class, 'post'); } public function index(): View { $posts = Post::latest()->paginate(10); return view('posts.index', compact('posts')); } public function store(Request $request): RedirectResponse { $post = $request->user()->posts()->create( $request->validate([ 'title' => ['required', 'string', 'max:255'], 'body' => ['required', 'string'], ]) ); return redirect()->route('posts.show', $post); } public function update(Request $request, Post $post): RedirectResponse { $post->update( $request->validate([ 'title' => ['required', 'string', 'max:255'], 'body' => ['required', 'string'], ]) ); return redirect()->route('posts.show', $post); } public function destroy(Post $post): RedirectResponse { $post->delete(); return redirect()->route('posts.index'); }}
Gate: einfache Berechtigungsentscheidungen ohne Model-Bezug, zum Beispiel für den Zugriff auf ein Admin-Dashboard oder für globale Konfigurationsrechte.
Policy: Berechtigungen für CRUD-Operationen an einem Model. Legen Sie pro Ressource wie Post, Order oder Comment eine Policy-Klasse an.
Häufig genutzte API
// Prüfung über ein GateGate::allows('update-post', $post); // true/falseGate::denies('update-post', $post); // true/falseGate::authorize('update-post', $post); // Ausnahme bei fehlender Berechtigung// Prüfung am User-Model$user->can('update', $post); // true/false$user->cannot('update', $post); // true/false// Prüfung im ControllerGate::authorize('update', $post); // 403 bei fehlender Berechtigung// Prüfung in Blade@can('update', $post) ... @endcan@cannot('update', $post) ... @endcannot
Häufig genutzte Artisan-Befehle
# Leere Policy erzeugenphp artisan make:policy PostPolicy# Mit passenden CRUD-Methoden für das Model erzeugenphp artisan make:policy PostPolicy --model=Post