Een gebruiker moet zijn eigen bericht kunnen bewerken, maar dat van iemand anders niet; een redacteur moet reacties kunnen verwijderen terwijl een gewoon lid dat niet kan. Laravel-autorisatie stelt je in staat om precies dit soort regels op één plek te verzamelen, zonder je bedrijfslogica te vervuilen. In deze gids lopen we door wanneer je een Policy versus een Gate gebruikt, hoe je modelgebaseerde toegangscontrole bouwt, en hoe je die toepast in je controllers, in Blade en in de API-laag.
Authenticatie en autorisatie zijn niet hetzelfde
Laten we eerst de twee begrippen scheiden. Authenticatie beantwoordt de vraag "wie ben je?"; dat regelen het inlogscherm, het wachtwoord en de sessie. Autorisatie beantwoordt de vraag "mag je dit doen?". Een gebruiker kan ingelogd zijn en toch geen recht hebben om de factuur van een andere gebruiker te bekijken. Laravel biedt twee belangrijke hulpmiddelen voor autorisatie: de Gate en de Policy.
Wanneer een Gate, wanneer een Policy
Beide gebruiken dezelfde motor, maar hun toepassingen verschillen:
- Gate — ideaal voor eenvoudige, brede rechten die niet aan een specifiek model gebonden zijn. Bijvoorbeeld "toegang tot het beheerpaneel" of "site-instellingen wijzigen". Gates zijn closure-gebaseerd en worden meestal gedefinieerd in
AppServiceProvider. - Policy — verzamelt de rechten rond één Eloquent-model (bekijken, aanmaken, bijwerken, verwijderen) in één klasse. Het is de juiste keuze voor de CRUD-autorisatie van modellen zoals
Post,InvoiceofProject.
Praktische regel: is het recht gebonden aan een modelrij, gebruik dan een Policy; zo niet, een Gate.
Een eenvoudig recht definiëren met een Gate
Een regel die niet aan een model gebonden is, kun je rechtstreeks als Gate definiëren. De eerste parameter van de closure is altijd de geauthenticeerde gebruiker:
use Illuminate\Support\Facades\Gate;
use App\Models\User;
public function boot(): void
{
Gate::define('access-admin', function (User $user) {
return $user->is_admin;
});
}
Om het te controleren gebruik je Gate::allows() of Gate::denies():
if (Gate::allows('access-admin')) {
// toon de paneelinhoud
}
Een Policy maken voor modelgebaseerde toegangscontrole
De echte kracht zit in Policies. Er een genereren voor een model is één enkel commando:
php artisan make:policy PostPolicy --model=Post
De --model-vlag genereert de standaardmethoden zoals view, create, update en delete als skelet. Vervolgens vul je ze in volgens je bedrijfsregels:
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
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;
}
}
Vanaf Laravel 11 worden policies automatisch ontdekt zolang je de naamgevingsconventie volgt (App\Models\Post → App\Policies\PostPolicy); extra registratie is niet nodig. Heb je een andere koppeling nodig, dan kun je die handmatig binden met Gate::policy(Post::class, PostPolicy::class).
Een Policy gebruiken in een controller
Binnen een controller is de schoonste aanpak de authorize-methode. Als de regel niet wordt voldaan, gooit Laravel automatisch een 403-respons:
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
$post->update($request->validated());
return redirect()->route('posts.show', $post);
}
Wil je alle CRUD-methoden in één regel koppelen, gebruik dan authorizeResource in de constructor van de controller; die bindt de resource-controllermethoden automatisch aan de policymethoden:
public function __construct()
{
$this->authorizeResource(Post::class, 'post');
}
Toepassen in Blade en de API-laag
Autorisatie mag niet alleen in de controller blijven. Om een knop te verbergen voor een gebruiker zonder rechten in Blade, gebruik je de @can-directive:
@can('update', $post)
<a href="{{ route('posts.edit', $post) }}">Bewerken</a>
@endcan
Om routes in bulk te beschermen voor API- en formulierverzoeken, doet de can-middleware het werk:
Route::put('/posts/{post}', [PostController::class, 'update'])
->middleware('can:update,post');
Je kunt ook controleren via een gebruikersobject: $user->can('update', $post). Dit is handig om een "mag bewerken?"-vlag naar de frontend te sturen in een JSON-respons.
De before-hook en veelgemaakte fouten
Wil je dat beheerders alles kunnen doen, voeg dan een before-methode toe aan de policy. Die draait vóór alle andere controles en slaat de rest over als hij true teruggeeft:
public function before(User $user, string $ability): ?bool
{
return $user->is_admin ? true : null;
}
null teruggeven is hier cruciaal: geef je false terug, dan draaien de andere methoden nooit en blokkeer je iedereen die geen beheerder is. Andere veelgemaakte fouten: vergeten de parameter nullable te maken als ?User $user voor gasten (niet-geauthenticeerd), en authorize verwarren met can — de eerste gooit een exception terwijl de tweede een boolean teruggeeft.
Veelgestelde vragen
Moet ik een Policy of een Gate gebruiken?
Is het recht gebonden aan een rij van een specifiek Eloquent-model (bijvoorbeeld "bewerk dit bericht"), gebruik dan een Policy. Voor algemene rechten die niet aan een model gebonden zijn (bijvoorbeeld "toegang tot het paneel"), blijft een Gate eenvoudiger.
Moet ik policies handmatig registreren?
Voor Laravel 11+ niet; ze worden automatisch ontdekt zolang je de naamgevingsconventie volgt. Je hebt Gate::policy() alleen nodig voor een afwijkende model-policy-koppeling.
Kan ik een eigen bericht teruggeven in plaats van een kale 403?
Ja. Door Illuminate\Auth\Access\Response::deny('bericht') terug te geven vanuit een policymethode kun je eigen fouttekst en een statuscode meegeven, en gebruik je Response::allow() in plaats van true.
Autorisatie vanaf het begin goed opzetten houdt je project veilig naarmate het groeit. Wil je nette, onderhoudbare toegangscontrole in je Laravel-project opzetten, neem dan contact met me op.