Passer au contenu principal

Différence entre authentification et autorisation

L’authentification vérifie « qui » est l’utilisateur (par exemple via la connexion). L’autorisation décide « ce qu’il peut faire » : n’éditer que ses propres publications, seuls les administrateurs modifient les paramètres, etc. Après avoir implémenté la connexion via l’authentification, l’étape suivante est l’autorisation.
Laravel propose deux approches d’autorisation : les Gates et les Policies. Le choix dépend de votre cas d’usage.
Guide de choix
ScénarioRecommandation
Décision simple non liée à un modèleGate
Gestion CRUD sur un modèlePolicy
Contrôle d’accès au dashboard adminGate
Droits CRUD sur les publications d’un blogPolicy

Gates

Les Gates sont des vérifications d’autorisation simples basées sur des closures. Idéales pour les jugements non liés à un modèle particulier.

Flux d’autorisation via Gate

Définir une Gate

Définissez la Gate dans la méthode boot de App\Providers\AppServiceProvider via Gate::define().
// 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;
    });
}
La closure reçoit toujours l’utilisateur authentifié en premier argument, puis le modèle ou d’autres informations.

Contrôler la permission

Dans un contrôleur, utilisez Gate::allows() ou Gate::denies().
use Illuminate\Support\Facades\Gate;

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

    // Mise à jour...

    return redirect('/posts');
}

Gate::authorize() pour lever une exception

Pour retourner automatiquement une réponse 403 en cas d’échec, utilisez Gate::authorize() (pas besoin d’écrire abort(403)).
public function update(Request $request, Post $post): RedirectResponse
{
    Gate::authorize('update-post', $post);

    // Ici la permission est accordée
    // Mise à jour...

    return redirect('/posts');
}
Gate::authorize() lève Illuminate\Auth\Access\AuthorizationException en cas de refus, que Laravel convertit automatiquement en 403.

Bypass administrateur (before)

Pour donner tous les droits aux administrateurs, utilisez Gate::before().
use App\Models\User;
use Illuminate\Support\Facades\Gate;

public function boot(): void
{
    // $ability contient le nom de la Gate en cours ('update-post', etc.)
    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;
    });
}
Si la closure before retourne une valeur non nulle, cette valeur devient le résultat. Si elle retourne null (ou rien), le contrôle normal se poursuit.

@can / @cannot dans Blade

Dans les templates, les directives @can et @cannot sont pratiques.
@can('update-post', $post)
    <a href="{{ route('posts.edit', $post) }}">Modifier</a>
@endcan

@cannot('update-post', $post)
    <p>Vous n'avez pas la permission de modifier cette publication.</p>
@endcannot

Policies

Une Policy regroupe la logique d’autorisation d’un modèle particulier dans une classe. Pour gérer les droits CRUD sur Post, les Policies conviennent mieux que les Gates.

Flux d’autorisation via Policy

Générer une Policy

Utilisez make:policy.
php artisan make:policy PostPolicy
Pour générer les méthodes CRUD standard, utilisez --model.
php artisan make:policy PostPolicy --model=Post
app/Policies/PostPolicy.php est créé.

Détection automatique modèle / policy

Par défaut, Laravel détecte la Policy selon la convention de nommage.
  • Modèle : app/Models/Post.php
  • Policy : app/Policies/PostPolicy.php
Aucun enregistrement manuel n’est nécessaire si vous respectez la convention.
Sinon, ou pour enregistrer manuellement, utilisez Gate::policy() dans AppServiceProvider::boot.
use App\Models\Post;
use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;

Gate::policy(Post::class, PostPolicy::class);
Sous Laravel 13, vous pouvez aussi utiliser l’attribut #[UsePolicy].
use App\Policies\PostPolicy;
use Illuminate\Database\Eloquent\Attributes\UsePolicy;

#[UsePolicy(PostPolicy::class)]
class Post extends Model {}

Implémenter les méthodes

Une Policy générée avec --model contient les méthodes CRUD standard.
<?php

namespace App\Policies;

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

class PostPolicy
{
    /**
     * Peut consulter la liste des publications ?
     */
    public function viewAny(User $user): bool
    {
        return true; // Tout utilisateur authentifié
    }

    /**
     * Peut consulter une publication ?
     */
    public function view(User $user, Post $post): bool
    {
        return true;
    }

    /**
     * Peut créer une publication ?
     */
    public function create(User $user): bool
    {
        return true;
    }

    /**
     * Peut mettre à jour une publication ?
     */
    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id; // Uniquement ses propres publications
    }

    /**
     * Peut supprimer une publication ?
     */
    public function delete(User $user, Post $post): bool
    {
        return $user->id === $post->user_id;
    }
}

Bypass administrateur (before)

Les Policies acceptent aussi une méthode before.
/**
 * Contrôle préalable exécuté avant les autres méthodes.
 * $ability contient le nom de la méthode ('update', 'delete'...).
 */
public function before(User $user, string $ability): bool|null
{
    if ($user->isAdministrator()) {
        return true; // Tout est permis pour l'admin
    }

    return null; // Poursuivre avec la méthode normale
}
before n’est appelé que si la méthode correspondante existe dans la Policy. Sans méthode update, before n’est pas appelé non plus.

Ordre d’exécution du callback before

Utiliser une Policy dans un contrôleur

Méthode authorize()

Le contrôleur de base Laravel expose authorize() (utilisez Gate::authorize() sinon).
<?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);

        // Mise à jour...

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

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

        // Création...

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

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

        $post->delete();

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

authorizeResource() pour un contrôleur RESTful

authorizeResource() associe automatiquement chaque action du contrôleur à la méthode correspondante de la Policy.
<?php

namespace App\Http\Controllers;

use App\Models\Post;

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

    // Les méthodes index(), show(), create(), store(), edit(), update(), destroy()
    // sont automatiquement liées aux méthodes de policy correspondantes
}
Correspondance :
Action du contrôleurMéthode de Policy
indexviewAny
showview
create / storecreate
edit / updateupdate
destroydelete
authorizeResource() évite d’appeler authorize() dans chaque action. Idéal avec les contrôleurs de ressource REST.

Autorisation via middleware

Pour vérifier au niveau de la route, utilisez le middleware can.
use App\Models\Post;

// Accessible aux utilisateurs autorisés à mettre à jour
Route::put('/posts/{post}', [PostController::class, 'update'])
    ->middleware('can:update,post');

// Accessible aux utilisateurs autorisés à créer
Route::post('/posts', [PostController::class, 'store'])
    ->middleware('can:create,App\Models\Post');
Version plus concise avec la méthode can :
Route::put('/posts/{post}', [PostController::class, 'update'])
    ->can('update', 'post');

Utiliser une Policy dans Blade

Une fois la Policy enregistrée, @can / @cannot l’utilisent automatiquement.
{{-- Bouton d'édition visible uniquement pour les utilisateurs autorisés --}}
@can('update', $post)
    <a href="{{ route('posts.edit', $post) }}" class="btn">Modifier</a>
@endcan

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

{{-- Bouton de création --}}
@can('create', App\Models\Post::class)
    <a href="{{ route('posts.create') }}">Nouvelle publication</a>
@endcan

Exemple : gestion des droits d’un blog

Exemple d’application blog où « seul l’auteur peut modifier/supprimer sa publication ».
1

Générer la Policy

php artisan make:policy PostPolicy --model=Post
2

Implémenter les méthodes

<?php

namespace App\Policies;

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

class PostPolicy
{
    /**
     * Bypass administrateur.
     */
    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

Ajouter `authorizeResource()` au contrôleur

<?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');
    }
}
4

Contrôle des droits dans Blade

{{-- 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) }}">Modifier</a>
@endcan

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

Récapitulatif

  • Gate : jugements simples non liés à un modèle (accès au dashboard admin, droit global de configuration).
  • Policy : gestion CRUD sur un modèle (Post, Order, Comment, etc.).
// Gate
Gate::allows('update-post', $post);      // true/false
Gate::denies('update-post', $post);      // true/false
Gate::authorize('update-post', $post);   // exception en cas d'échec

// Depuis le modèle utilisateur
$user->can('update', $post);     // true/false
$user->cannot('update', $post);  // true/false

// Dans un contrôleur
Gate::authorize('update', $post);        // 403 si refus

// Dans Blade
@can('update', $post) ... @endcan
@cannot('update', $post) ... @endcannot
# Policy vide
php artisan make:policy PostPolicy

# Avec méthodes CRUD pour un modèle
php artisan make:policy PostPolicy --model=Post
Dernière modification le 13 juillet 2026