> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Autorisatie (gates en policies)

> Leer hoe je gebruikersrechten voor acties beheert met gates en policies in Laravel.

## Het verschil tussen authenticatie en autorisatie

**Authenticatie** controleert "wie" een gebruiker is. Het inlogproces is daar het bekendste voorbeeld van.
**Autorisatie** bepaalt "wat" die gebruiker mag doen. Denk aan controles zoals: je mag alleen je eigen posts bewerken, of alleen beheerders mogen instellingen wijzigen.

Heb je met [authenticatie](./authentication) een inlogfunctie geïmplementeerd, dan is autorisatie de volgende stap.

<Info>
  De autorisatiefunctionaliteit van Laravel biedt twee benaderingen: gates en policies. Welke je gebruikt hangt af van de use case.
</Info>

**Richtlijnen voor de keuze**

| Scenario                                                             | Aanbevolen |
| -------------------------------------------------------------------- | ---------- |
| Eenvoudige controles die niet aan een specifiek model gekoppeld zijn | Gate       |
| Rechtenbeheer voor CRUD-bewerkingen op een model                     | Policy     |
| Toegangscontrole voor een beheerdersdashboard                        | Gate       |
| Rechten voor het aanmaken, bewerken en verwijderen van blogposts     | Policy     |

## Gates

Gates zijn eenvoudige, closure-gebaseerde autorisatiechecks. Ze zijn geschikt voor rechtencontroles die niet aan een specifiek model gekoppeld zijn.

### Autorisatieflow met gates

```mermaid theme={null}
flowchart TD
    A["AppServiceProvider::boot()<br>(App\\Providers\\AppServiceProvider)"] --> B["Gate::define('ability', fn)<br>autorisatielogica registreren"]
    C["Autorisatiecheck vanuit de controller"] --> D{"Is Gate::before()<br>ingesteld?"}
    D -->|"ja"| E{"Returnwaarde van before()"}
    E -->|"true / false"| F["Resultaat van before() als eindoordeel gebruiken"]
    E -->|"null"| G["Closure van define() uitvoeren"]
    D -->|"nee"| G
    G --> H{"Returnwaarde van de closure"}
    H -->|"true"| I["✓ Toegang toegestaan"]
    H -->|"false"| J["✗ Toegang geweigerd"]
    F -->|"true"| I
    F -->|"false"| J
    J -->|"Gate::allows()"| K["Geeft false terug<br>→ roep zelf abort(403) aan"]
    J -->|"Gate::authorize()"| L["AuthorizationException<br>→ automatisch 403 Forbidden"]
```

### Een gate definiëren

Gates definieer je met `Gate::define()` in de `boot`-methode van `App\Providers\AppServiceProvider`.

```php theme={null}
// app/Providers/AppServiceProvider.php

use 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;
    });
}
```

De closure van een gate ontvangt altijd de momenteel geauthenticeerde gebruiker als eerste argument. Vanaf het tweede argument kun je extra informatie doorgeven, zoals het betreffende model.

### Rechten controleren met een gate

Om in een controller rechten te controleren met een gate gebruik je `Gate::allows()` of `Gate::denies()`.

```php theme={null}
use Illuminate\Support\Facades\Gate;

public function update(Request $request, Post $post): RedirectResponse
{
    if (! Gate::allows('update-post', $post)) {
        abort(403);
    }

    // Verwerking om de post bij te werken...

    return redirect('/posts');
}
```

### Een exceptie gooien met Gate::authorize()

Om automatisch een 403-response terug te geven wanneer de gebruiker geen rechten heeft, gebruik je `Gate::authorize()`. Zo hoef je geen `abort(403)` te schrijven.

```php theme={null}
public function update(Request $request, Post $post): RedirectResponse
{
    Gate::authorize('update-post', $post);

    // Met de juiste rechten kom je hier
    // Verwerking om de post bij te werken...

    return redirect('/posts');
}
```

<Tip>
  `Gate::authorize()` gooit een `Illuminate\Auth\Access\AuthorizationException` als de gebruiker geen rechten heeft. Laravel zet die automatisch om in een 403 HTTP-response.
</Tip>

### Beheerdersbypass (de before-methode)

Wil je beheerders alle rechten geven, gebruik dan `Gate::before()`.

```php theme={null}
use App\Models\User;
use Illuminate\Support\Facades\Gate;

public function boot(): void
{
    // $ability bevat de naam van de gate die wordt uitgevoerd ('update-post', enz.)
    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;
    });
}
```

Geeft de closure van `before` een andere waarde dan `null` terug, dan wordt dat resultaat het eindoordeel van de rechtencheck. Geeft de closure `null` of niets terug, dan gaat de normale gate-check verder.

### @can / @cannot in Blade-templates

Voor gate-checks in templates zijn de directives `@can` en `@cannot` handig.

```blade theme={null}
@can('update-post', $post)
    <a href="{{ route('posts.edit', $post) }}">Bewerken</a>
@endcan

@cannot('update-post', $post)
    <p>Je hebt geen rechten om deze post te bewerken.</p>
@endcannot
```

## Policies

Een policy bundelt de autorisatielogica voor een specifiek model in een klasse. Voor het rechtenbeheer van aanmaken, bekijken, bewerken en verwijderen op het `Post`-model is een policy geschikter dan een gate.

### Autorisatieflow met policies

```mermaid theme={null}
flowchart TD
    A["HTTP-request"] --> B["Controller"]
    B --> C["Gate::authorize('update', $post)"]
    C --> D{"Is PostPolicy::before()<br>gedefinieerd?"}
    D -->|"ja"| E{"Returnwaarde van before()"}
    E -->|"true / false"| F["Resultaat van before() als eindoordeel gebruiken"]
    E -->|"null"| G["PostPolicy::update(User, Post) uitvoeren"]
    D -->|"nee"| G
    G --> H{"$user->id === $post->user_id?"}
    H -->|"true"| I["✓ Verwerking gaat verder"]
    H -->|"false"| J["✗ AuthorizationException<br>→ 403 Forbidden"]
    F -->|"true"| I
    F -->|"false"| J
```

### Een policy genereren

Met het Artisan-commando `make:policy` genereer je een policy-klasse.

```shell theme={null}
php artisan make:policy PostPolicy
```

Om een sjabloon te genereren met alle CRUD-methoden voor een model gebruik je de optie `--model`.

```shell theme={null}
php artisan make:policy PostPolicy --model=Post
```

Er wordt een bestand `app/Policies/PostPolicy.php` gegenereerd.

### Automatische detectie van modellen en policies

Laravel detecteert policies standaard automatisch op basis van naamgevingsconventies.

* Model: `app/Models/Post.php`
* Policy: `app/Policies/PostPolicy.php`

Volg je deze naamgevingsconventie, dan hoef je de policy niet te registreren.

<Info>
  Als je de naamgevingsconventie niet volgt of handmatig wilt registreren, gebruik je `Gate::policy()` in de `boot`-methode van de `AppServiceProvider`.

  ```php theme={null}
  use App\Models\Post;
  use App\Policies\PostPolicy;
  use Illuminate\Support\Facades\Gate;

  Gate::policy(Post::class, PostPolicy::class);
  ```

  In Laravel 13 kun je een policy ook declaratief registreren door het `#[UsePolicy]`-attribuut aan het model toe te voegen.

  ```php theme={null}
  use App\Policies\PostPolicy;
  use Illuminate\Database\Eloquent\Attributes\UsePolicy;

  #[UsePolicy(PostPolicy::class)]
  class Post extends Model {}
  ```
</Info>

### Policy-methoden implementeren

Een policy die je met de optie `--model` genereert, bevat methoden voor de standaard CRUD-acties.

```php theme={null}
<?php

namespace App\Policies;

use App\Models\Post;
use App\Models\User;

class PostPolicy
{
    /**
     * Mag de gebruiker de lijst met posts bekijken?
     */
    public function viewAny(User $user): bool
    {
        return true; // Elke geauthenticeerde gebruiker mag kijken
    }

    /**
     * Mag de gebruiker een specifieke post bekijken?
     */
    public function view(User $user, Post $post): bool
    {
        return true; // Elke geauthenticeerde gebruiker mag kijken
    }

    /**
     * Mag de gebruiker een post aanmaken?
     */
    public function create(User $user): bool
    {
        return true; // Elke geauthenticeerde gebruiker mag posten
    }

    /**
     * Mag de gebruiker een post bijwerken?
     */
    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id; // Alleen eigen posts bewerken
    }

    /**
     * Mag de gebruiker een post verwijderen?
     */
    public function delete(User $user, Post $post): bool
    {
        return $user->id === $post->user_id; // Alleen eigen posts verwijderen
    }
}
```

### Beheerdersbypass (de before-methode)

Ook in een policy kun je een `before`-methode definiëren om beheerders alle rechten te geven.

```php theme={null}
/**
 * Voorafgaande check die vóór de andere policy-methoden wordt uitgevoerd
 * $ability bevat de naam van de policy-methode ('update', 'delete', enz.)
 */
public function before(User $user, string $ability): bool|null
{
    if ($user->isAdministrator()) {
        return true; // Beheerders mogen alle acties uitvoeren
    }

    return null; // Bij null gaat het door naar de normale policy-methode
}
```

<Warning>
  De `before`-methode wordt alleen aangeroepen als de policy-klasse een methode heeft die overeenkomt met de actie. Bestaat de `update`-methode bijvoorbeeld niet, dan wordt `before` ook niet aangeroepen.
</Warning>

### Uitvoervolgorde van de before-callback

```mermaid theme={null}
flowchart TD
    A["Autorisatiecheck start<br>authorize('update', $post)"] --> B["PostPolicy::before() uitvoeren"]
    B --> C{"Is de returnwaarde null?"}
    C -->|"anders dan null (true / false)"| D["Resultaat van before() als eindoordeel gebruiken"]
    C -->|"null"| E["Normale policy-methode uitvoeren<br>update() / delete() enz."]
    E --> F{"Returnwaarde van de policy-methode"}
    F -->|"true"| G["✓ Toegang toegestaan"]
    F -->|"false"| H["✗ Toegang geweigerd → 403"]
    D -->|"true (beheerdersbypass)"| G
    D -->|"false"| H
```

## Policies gebruiken in controllers

### De authorize()-methode

Controllers van Laravel hebben een `authorize()`-helpermethode (gebruik je de basiscontroller niet, dan gebruik je `Gate::authorize()`).

<Tabs>
  <Tab title="Gate::authorize()">
    ```php theme={null}
    <?php

    namespace 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);

            // Verwerking om de post bij te werken...

            return redirect()->route('posts.index');
        }

        public function store(Request $request): RedirectResponse
        {
            Gate::authorize('create', Post::class);

            // Verwerking om de post aan te maken...

            return redirect()->route('posts.index');
        }

        public function destroy(Post $post): RedirectResponse
        {
            Gate::authorize('delete', $post);

            $post->delete();

            return redirect()->route('posts.index');
        }
    }
    ```
  </Tab>

  <Tab title="User::can() / cannot()">
    ```php theme={null}
    <?php

    namespace 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);
            }

            // Verwerking om de post bij te werken...

            return redirect()->route('posts.index');
        }
    }
    ```
  </Tab>
</Tabs>

### RESTful-policies in één keer registreren met authorizeResource()

Roep je `authorizeResource()` aan in de constructor, dan worden de policy-methoden automatisch gekoppeld aan de bijbehorende acties van de controller.

```php theme={null}
<?php

namespace App\Http\Controllers;

use App\Models\Post;

class PostController extends Controller
{
    public function __construct()
    {
        $this->authorizeResource(Post::class, 'post');
    }

    // De bijbehorende policy-methoden worden automatisch toegepast op
    // index(), show(), create(), store(), edit(), update() en destroy()
}
```

De koppeling tussen controlleracties en policy-methoden:

| Controlleractie    | Policy-methode |
| ------------------ | -------------- |
| `index`            | `viewAny`      |
| `show`             | `view`         |
| `create` / `store` | `create`       |
| `edit` / `update`  | `update`       |
| `destroy`          | `delete`       |

<Tip>
  Met `authorizeResource()` hoef je niet in elke actie afzonderlijk `authorize()` te schrijven. Vooral in combinatie met RESTful resource controllers is dit handig.
</Tip>

## Autorisatie via middleware

Voor autorisatiechecks op routeniveau gebruik je de `can`-middleware.

```php theme={null}
use App\Models\Post;

// Alleen toegankelijk voor gebruikers die de post mogen bijwerken
Route::put('/posts/{post}', [PostController::class, 'update'])
    ->middleware('can:update,post');

// Alleen toegankelijk voor gebruikers die posts mogen aanmaken
Route::post('/posts', [PostController::class, 'store'])
    ->middleware('can:create,App\Models\Post');
```

Een beknoptere notatie met de `can`-methode:

```php theme={null}
Route::put('/posts/{post}', [PostController::class, 'update'])
    ->can('update', 'post');
```

## Policies gebruiken in Blade-templates

Zodra een policy is geregistreerd, wordt die ook automatisch gebruikt door de Blade-directives `@can` / `@cannot`.

```blade theme={null}
{{-- De bewerkknop van de post alleen tonen aan gebruikers met rechten --}}
@can('update', $post)
    <a href="{{ route('posts.edit', $post) }}" class="btn">Bewerken</a>
@endcan

{{-- Hetzelfde voor de verwijderknop --}}
@can('delete', $post)
    <form method="POST" action="{{ route('posts.destroy', $post) }}">
        @csrf
        @method('DELETE')
        <button type="submit">Verwijderen</button>
    </form>
@endcan

{{-- Knop voor een nieuwe post --}}
@can('create', App\Models\Post::class)
    <a href="{{ route('posts.create') }}">Nieuwe post</a>
@endcan
```

## Praktijkvoorbeeld: rechtenbeheer voor blogposts

Een voorbeeld waarin we in een blogapp de rechten "alleen de auteur mag zijn eigen artikelen bewerken en verwijderen" implementeren.

<Steps>
  <Step title="Genereer een policy">
    ```shell theme={null}
    php artisan make:policy PostPolicy --model=Post
    ```
  </Step>

  <Step title="Implementeer de policy-methoden">
    ```php theme={null}
    <?php

    namespace App\Policies;

    use App\Models\Post;
    use App\Models\User;

    class PostPolicy
    {
        /**
         * Beheerders alle rechten geven
         */
        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;
        }
    }
    ```
  </Step>

  <Step title="Voeg authorizeResource() toe aan de controller">
    ```php theme={null}
    <?php

    namespace 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');
        }
    }
    ```
  </Step>

  <Step title="Voeg rechtenchecks toe aan het Blade-template">
    ```blade theme={null}
    {{-- resources/views/posts/show.blade.php --}}
    <h1>{{ $post->title }}</h1>
    <p>{{ $post->body }}</p>
    <p>Auteur: {{ $post->user->name }}</p>

    @can('update', $post)
        <a href="{{ route('posts.edit', $post) }}">Bewerken</a>
    @endcan

    @can('delete', $post)
        <form method="POST" action="{{ route('posts.destroy', $post) }}">
            @csrf
            @method('DELETE')
            <button type="submit">Verwijderen</button>
        </form>
    @endcan
    ```
  </Step>
</Steps>

## Samenvatting

<AccordionGroup>
  <Accordion title="Wanneer gebruik je gates en wanneer policies?">
    * **Gates**: eenvoudige rechtenchecks die niet aan een specifiek model gekoppeld zijn. Bijvoorbeeld toegang tot een beheerdersdashboard of rechten om globale instellingen te wijzigen.
    * **Policies**: rechtenbeheer voor CRUD-bewerkingen op modellen. Maak per resource zoals `Post`, `Order` en `Comment` een policy-klasse.
  </Accordion>

  <Accordion title="Overzicht van veelgebruikte API's">
    ```php theme={null}
    // Controleren met een gate
    Gate::allows('update-post', $post);      // true/false
    Gate::denies('update-post', $post);      // true/false
    Gate::authorize('update-post', $post);   // exceptie bij falen

    // Controleren via het user-model
    $user->can('update', $post);     // true/false
    $user->cannot('update', $post);  // true/false

    // Controleren in de controller
    Gate::authorize('update', $post);        // 403 bij falen

    // Controleren in Blade
    @can('update', $post) ... @endcan
    @cannot('update', $post) ... @endcannot
    ```
  </Accordion>

  <Accordion title="Veelgebruikte Artisan-commando's">
    ```shell theme={null}
    # Een lege policy genereren
    php artisan make:policy PostPolicy

    # Genereren met CRUD-methoden voor een model
    php artisan make:policy PostPolicy --model=Post
    ```
  </Accordion>
</AccordionGroup>


## Related topics

- [Versleuteling (Encryption)](/nl/encryption.md)
- [Laravel Telescope](/nl/telescope.md)
- [PHP-attributes voor controllers](/nl/advanced/controller-attributes.md)
- [Laravel Horizon](/nl/horizon.md)
- [Foutafhandeling](/nl/error-handling.md)
