Le contrôle d’accès aux ressources est fondamental au sein d’une application. Cette sécurité permet de garantir que le voisin n’ira pas consulter votre relevé de compte ou bien qu’il ne pourra pas changer votre photo de profil sur votre réseau social préféré.
Sommaire
- Création du modèle
- Création du contrôleur
- Création des vues
- Validation des données
- Contrôle d’accès
- Les tests
Les cas d’usage
Sur notre application de gestion de restaurants, nous allons garantir à nos restaurateurs qu’ils sont seuls à pouvoir gérer leur périmètre, excepté l'admin, en appliquant ces contrôles :
- Un visiteur peut consulter la liste des restaurants et accéder à la fiche d’un restaurant particulier.
- Un restaurateur peut créer un restaurant et éditer ou supprimer un de ses restaurants
- Un administrateur peut supprimer n’importe quel restaurant
La génération de la Policy
Les Policies sont des classes dont la vocation est de vérifier les accès à un modèle particulier.
Les accès sont définis en fonction des actions souhaité sur le modèle.
Une commande existe pour nous simplifier la création de notre Policy
. On peut même y définir le modèle cible, comme ceci :
1php artisan make:policy RestaurantPolicy --model=Restaurant
On obtient le fichier app/Policies/RestaurantPolicy.php
préalablement remplit avec toutes les actions possibles, il nous reste plus qu’à y intégrer la logique en fonction de nos cas d’usages en passant en revue chacune d’une méthode
Dans le cas des méthodes viewAny
et view
étant donné que l’on souhaite que tout le monde puisse accéder à ces pages nous devons rendre la fourniture de notre instance User
optionnelle pour le cas de l’utilisateur non-authentifié. Pour le contenu de la méthode, on retourne tout simplement true
car nous n’avons pas de contrainte particulière :
1public function viewAny(?User $user)2{3 return true;4}5 6public function view(?User $user, Restaurant $restaurant)7{8 return true;9}
On enchaîne avec la méthode create
, comme seul un restaurateur peut créer des restaurants nous avons y vérifier que le rôle de l’utilisateur fournit est bien owner
:
1public function create(User $user)2{3 return $user->isOwner();4}
Ensuite, on traite la méthode update
où a été définit que seul le propriétaire du restaurant ciblé peut agir, chose qu’on peut garantir en comparant les identifiants :
1public function update(User $user, Restaurant $restaurant)2{3 return $user->id === $restaurant->user_id;4}
Enfin, la méthode delete
où l’on souhaite que le restaurateur ainsi qu’un admin puisse déclencher la suppression d’un restaurant :
1public function delete(User $user, Restaurant $restaurant)2{3 return $user->isAdmin() || $user->id === $restaurant->user_id;4}
Voilà, on a répondu à nos divers cas d’usages.
L’utilisation au sein du contrôleur
On passe dorénavant à l’utilisation de notre Policy
.
Il est possible de contrôler l’accès d’un utilisateur de plusieurs manières au sein du contrôleur. Dans le cas d’une utilisation sur une ou quelques méthodes spécifiques, il existe la méthode authorize
:
1public function update(Request $request, Restaurant $restaurant) 2{ 3 $this->authorize('update', $restaurant); 4 5 // L'utilisateur est autorisé à éditer le restaurant ... 6} 7 8public function create(Request $request) 9{10 $this->authorize('create', Restaurant::class);11 12 // L'utilisateur est autorisé à créer un restaurant ...13}
Dans le cas où on souhaiterait complètement déléguer le contrôle d’accès à la Policy, on peut définir la ressource cible dans le constructeur du contrôleur comme ceci :
1public function __construct()2{3 $this->authorizeResource(Restaurant::class, 'restaurant');4}
L’alternative via les routes
D’une autre manière, il est possible d’appliquer les contrôles d’accès directement sur les routes via la méthode middleware
:
1Route::get('/restaurants', [RestaurantController::class, 'index']) 2 ->name('restaurants.index') 3 ->middleware(['can:viewAny,App\Models\Restaurant']); 4 5Route::get('/restaurants/create', [RestaurantController::class, 'create']) 6 ->name('restaurants.create') 7 ->middleware(['auth', 'can:create,App\Models\Restaurant']); 8 9Route::get('/restaurants/{restaurant}/edit', [RestaurantController::class, 'edit'])10 ->name('restaurants.edit')11 ->middleware(['auth', 'can:update,restaurant']);12 13// ...
Accommoder l’affichage en fonction des accès
Pour des raisons d’expérience utilisateur, il est aussi important d’afficher à l’utilisateur uniquement ce qu’il est en droit de faire. Pour cela Blade fournit la directive @can
:
1@can('create', App\Models\Restaurant::class)2 <a href="{{ route('restaurants.create') }}">Créer un restaurant</a>3@endcan4 5@can('update', $restaurant)6 <a href="{{ route('restaurants.edit', $restaurant) }}">Editer le restaurant</a>7@endcan
Nous avons dorénavant sécurisé les accès aux restaurants, c’est la fin de ce chapitre.
Dans le prochain épisode…
Pour ce dernier épisode, nous allons nous assurer du bon fonctionnement de notre application à travers les tests !
Source : https://github.com/laravel-fr/support-les-bases/tree/v5
A lire
Autres articles de la même catégorie
Monitorer son site web
Est-ce que votre site est actuellement opérationnel ? On découverte un outil simple qui vous permettra de la savoir à tout moment !
William Suppo
Envoyer des notifications sur Discord
A travers ce tutoriel, nous allons découvrir comment envoyer une notification sur Discord lorsqu’un événement ce produit.
William Suppo
Les bases 3/6 : Création des vues
Découverte du moteur de vue Blade
William Suppo