Dans ce tutoriel je vous propose de réfléchir à la mise en place d'un système de permissions en PHP. L'objectif est de mettre en place un système qui nous permettra de vérifier si l'utilisateur est autorisée à effectuer une action spécifique au sein de notre application.
00:00 Présentation des systèmes de permissions existants
09:50 On crée notre propre système
Les stratégies
A travers mon exploration de différents frameworks / technologies j'ai pu découvrir différentes approches du problèmes.
Permissions hiérarchique
Cette stratégie consiste à créer différents rôles en leur attribuant un nombre spécifique (plus le nombre est important plus la permission est élevée).
Les utilisateurs se voient alors attribués un niveau en fonction de ces constantes. On peut ensuite utiliser ce niveau pour contrôler l'accès à une fonctionnalité.
Cette approche suffit pour des cas simples mais s'avère limitée pour des cas plus complexes, surtout lorsque de la logique vient s'ajouter aux vérifications (par exemple un utilisateur ne peut modifier que ses articles, mais un administrateur peut éditer tous les articles) ou lorsque les permissions ne sont pas hiérarchique.
Les roles
Une autre idée est de créer des rôles pour les utilisateurs et d'associer une série de permissions à ces rôles.
On peut aussi ajouter des conditions si on souhaite plus de flexibilité dans les conditions d'accès à une certaines permissions.
Cette approche est déjà beaucoup plus intéréssante car elle permet de gérer des rôles complètements différents et l'utilisateur peut même se voir attribuer plusieurs rôles. En revanche cela implique de créer un objet qui va contenir l'ensemble des permission en amont et lors de la monté en complexité de l'application le nombre de permissions / conditions peut devenir difficile à gérer.
Les capacités
Cette approche est utilisée par la librairie CanCanCan et consiste à définir les capacités offertes aux utilisateur en amont en fonction de son profil ou de son rôle.
Cette approche se rapproche beaucoup de l'approche précédante mais la déclaration des permissions se fait de manière différente en associant au nom de la permission l'objet qui est la cible de la demande. Une version PHP ressemblerait à ça :
Comme pour la méthode précédente le problème est la multiplication des règles lors de la montée en complexité des permissions et cela peut être compliqué de s'y retrouver dans la définition des règles / conditions.
Les politiques
Cette approche est visible sur le framework Laravel et consiste à définir un système de politique d'accès. Cette approche permet de se focaliser sur la cible de la demande de permission plutôt que de centrer les choses autour de l'utilisateur.
Une fois cette politique définie elle peut être associée à une classe (souvent un modèle) :
Ainsi, lorsque la cible d'une permission est un article, la méthode correspondant au nom de la permission sera appelée afin de donner (ou non) l'autorisation à l'utilisateur.
Cette approche est intéréssante car elle permet de créer des politiques génériques qui peuvent être appliquées à plusieurs modèles. En revanche, des permissions transversales sont toujours problématiques (le super administrateur à accès à tous le site par exemple) et il faudra supplémenter ce système avec un système plus classique similaire à CanCanCan. Laravel propose un système de gate imitant l'approche précédente.
Les voters
Ce système est plus basique que les précédents et consiste à définir la gestion des permissions comme un système de votes. On commence par enregistrer une série de Voter dans notre application. Lorsqu'une permission est demandée l'ensemble des Voter vont être consultés et ils vont indiquer si ils participent ou non au vote. Les Voter qui participent vont ensuite voter pour donner ou non leur accord sur la permission demandée. Enfin, une politique de réconciliation va être utilisée pour définir si la permission est accordée ou non. Il existe plusieurs stratégie de réconciliation
- Affirmative. La permission est accordée dès lors qu'un
Votervote OUI. - Unanime. La permission est accordée si tous les
Votervotent OUI. - Consensus. La permission est accordée si les
Votervotant OUI sont majoritaires.
La mise en place d'un tel système est très simple. L'interface d'un voter lui permet de déclarer sa participation à un vote, et le résultat de son vote
La classe permettant de vérifier les permissions (on utilise ici la stratégie Affirmative) sera composée d'une méthode permettant l'enregistrement de Voter et une méthode permettant de les consulter pour une demande d'autorisation.
Cette stratégie offre l'avantage de permettre la définition de permission transversale très simplement
La détection d'une interface peut aussi servir à définir une logique de permission générale.
Il est aussi d'adapter cette solution pour la combiner à une autre approche (par exemple un système de permission ACL en base de données).
Ce système est du coup intéressant car il peut servir de base solide pour définir des permissions avec différentes politiques. En revanche, il peut être parfois difficile de comprendre pourquoi une permission a été donnée ou refusée. Il ne faudra donc pas hésiter à greffer à ce système un outil de debug qui permettra de comprendre pourquoi une permission a été attribuée (ou non) en indiquant les Voter qui ont participés et les résultats de leur vote.