aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Développement Web

Autorisation Laravel : guide des Policy et Gate

Un utilisateur doit pouvoir modifier son propre article mais pas celui d'un autre ; un éditeur doit pouvoir supprimer des commentaires alors qu'un membre ordinaire ne le peut pas. L'autorisation Laravel vous permet de regrouper exactement ce type de règles à un seul endroit, sans polluer votre logique métier. Dans ce guide, nous verrons quand utiliser une Policy plutôt qu'une Gate, comment construire un contrôle d'accès par modèle, et comment l'appliquer dans vos controllers, dans Blade et dans la couche API.

Authentification et autorisation ne sont pas la même chose

Distinguons d'abord les deux notions. L'authentification répond à « qui êtes-vous ? » ; c'est le rôle de l'écran de connexion, du mot de passe et de la session. L'autorisation répond à « avez-vous le droit de faire cela ? ». Un utilisateur peut être connecté et n'avoir tout de même aucun droit de consulter la facture d'un autre. Laravel propose deux outils principaux pour l'autorisation : la Gate et la Policy.

Quand utiliser une Gate, quand utiliser une Policy

Les deux utilisent le même moteur, mais leurs cas d'usage diffèrent :

  • Gate — idéale pour des permissions simples et larges qui ne sont pas liées à un modèle précis. Par exemple « accéder au panneau d'administration » ou « modifier les réglages du site ». Les gates reposent sur des closures et se définissent généralement dans AppServiceProvider.
  • Policy — regroupe dans une seule classe les permissions tournant autour d'un même modèle Eloquent (consulter, créer, mettre à jour, supprimer). C'est le bon choix pour les autorisations CRUD de modèles comme Post, Invoice ou Project.

Règle pratique : si la permission est liée à une ligne de modèle, utilisez une Policy ; sinon, une Gate.

Définir une permission simple avec une Gate

Vous pouvez définir directement comme Gate une règle non liée à un modèle. Le premier paramètre de la closure est toujours l'utilisateur authentifié :

use Illuminate\Support\Facades\Gate;
use App\Models\User;

public function boot(): void
{
    Gate::define('access-admin', function (User $user) {
        return $user->is_admin;
    });
}

Pour la vérifier, vous utilisez Gate::allows() ou Gate::denies() :

if (Gate::allows('access-admin')) {
    // afficher le contenu du panneau
}

Créer une Policy pour le contrôle d'accès par modèle

La vraie puissance réside dans les Policy. En générer une pour un modèle tient en une seule commande :

php artisan make:policy PostPolicy --model=Post

Le drapeau --model génère le squelette des méthodes standard comme view, create, update et delete. Vous les complétez ensuite selon vos règles métier :

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

À partir de Laravel 11, les policies sont découvertes automatiquement tant que vous respectez la convention de nommage (App\Models\PostApp\Policies\PostPolicy) ; aucun enregistrement supplémentaire n'est nécessaire. Si vous avez besoin d'une autre correspondance, vous pouvez la lier manuellement avec Gate::policy(Post::class, PostPolicy::class).

Utiliser une Policy dans un controller

Dans un controller, l'approche la plus propre est la méthode authorize. Si la règle n'est pas satisfaite, Laravel lève automatiquement une réponse 403 :

public function update(Request $request, Post $post)
{
    $this->authorize('update', $post);

    $post->update($request->validated());

    return redirect()->route('posts.show', $post);
}

Pour mapper toutes les méthodes CRUD en une seule ligne, vous pouvez utiliser authorizeResource dans le constructeur du controller ; il lie automatiquement les méthodes du resource controller aux méthodes de la policy :

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

L'appliquer dans Blade et la couche API

L'autorisation ne doit pas rester uniquement dans le controller. Pour masquer un bouton à un utilisateur sans permission dans Blade, utilisez la directive @can :

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

Pour protéger des routes en masse côté API et formulaires, le middleware can fait l'affaire :

Route::put('/posts/{post}', [PostController::class, 'update'])
    ->middleware('can:update,post');

Vous pouvez aussi vérifier via un objet utilisateur : $user->can('update', $post). C'est pratique pour envoyer au frontend un indicateur « peut modifier ? » dans une réponse JSON.

Le hook before et les erreurs courantes

Si vous voulez que les administrateurs puissent tout faire, ajoutez une méthode before à la policy. Elle s'exécute avant toutes les autres vérifications et, si elle renvoie true, elle court-circuite le reste :

public function before(User $user, string $ability): ?bool
{
    return $user->is_admin ? true : null;
}

Renvoyer null ici est crucial : si vous renvoyez false, les autres méthodes ne s'exécutent jamais et vous bloquez tous ceux qui ne sont pas administrateurs. Autres erreurs fréquentes : oublier de rendre le paramètre nullable avec ?User $user pour les invités (non authentifiés), et confondre authorize et can — la première lève une exception tandis que la seconde renvoie un boolean.

Questions fréquentes

Dois-je utiliser une Policy ou une Gate ?

Si la permission est liée à une ligne d'un modèle Eloquent précis (par exemple « modifier cet article »), utilisez une Policy. Pour des permissions générales non liées à un modèle (par exemple « accéder au panneau »), une Gate reste plus simple.

Dois-je enregistrer les policies manuellement ?

Pour Laravel 11+, non ; elles sont découvertes automatiquement tant que vous respectez la convention de nommage. Vous n'avez besoin de Gate::policy() que pour une correspondance modèle-policy différente.

Puis-je renvoyer un message personnalisé au lieu d'un simple 403 ?

Oui. En renvoyant Illuminate\Auth\Access\Response::deny('message') depuis une méthode de policy, vous pouvez fournir un texte d'erreur personnalisé et un code de statut, et utiliser Response::allow() au lieu de true.

Bien configurer l'autorisation dès le départ garde votre projet en sécurité à mesure qu'il grandit. Pour mettre en place un contrôle d'accès propre et maintenable dans votre projet Laravel, contactez-moi.

Bu kategorideki tüm yazılar →

Devamı için