Symfony : Utiliser les Voters pour gérer des permissions

Le mécanisme pour gérer les permissions d'un utilisateur sur un objet donné
Lignes de code Symfony
29/02/2016

Symfony : Utiliser les Voters pour gérer des permissions

Il existe en Symfony un mécanisme (en fait il en existe plusieurs, mais celui-ci est recommandé depuis les versions les plus récentes) appelé Voter. Son but est de permettre ou non l’accès à un objet par l’utilisateur courant. C’est une relation utilisateur/objet régie par des conditions.

Des Voters ?

Il vous est sans doute arrivé d’utiliser ce bout de code pour récupérer l’utilisateur connecté s’il y en a un :

C’est un Voter qu’on utilise là pour vérifier qu’un utilisateur est connecté au site. 

La fonction isGranted permet d’utiliser le Voter, défini par une classe implémentant VoterInterface. On peut aussi utiliser is_granted(string, object) en Twig.

Les Voters ont été particulièrement utiles lorsque nous avons développé Citizers. En effet, le site est régi par toutes sortes de conditions qui donnent accès ou non à certaines fonctionnalités. Voici quelques exemples : 

  • ● Après avoir créé une solution à un problème donné, l’utilisateur peut l’éditer, tant qu’aucun autre utilisateur n’a commenté cette solution.
  • ● Un utilisateur peut voter (+1, -1) pour une solution proposée par un membre. Mais il ne peut voter que si le statut de la solution est Ouvert (On ne peut plus une fois que la solution passe en phase suivante qui est l’attente de réponse d’un Realizer)

Créer un Voter Custom

Créer et utiliser un Voter custom n’est pas difficile. Pour première étape, il faut créer une classe implémentant l’interface VoterInterface.

A noter

Dans la doc de Symfony, vous verrez que l'exemple est un peu différent car, pour plus de clarté, ils proposent d'étendre une classe qui, elle, implémente VoterInterface.

Je ne connaissais pas cette méthode à l'époque, mais ce n'est pas très grave, car cela se ressemble beaucoup.

Pour en revenir à l'interface VoterInterface, elle fournit trois méthodes :

  • ● supportsAttribute($attribute)
  • ● supportsClass($class)
  • ● vote(TokenInterface $token, $object, array $attributes)

La première permet de définir des « actions » différentes relatives au même objet, par exemple notre action de voter pour la solution, et celle de l’éditer. On définit des strings qui seront ensuite utilisées en premier argument de la fonction isGranted (ou is_granted en twig).

La 2e définit le type d’objet sur lequel on veut appliquer des conditions. Dans notre exemple, la classe Solution.

Dans la 3e méthode, c’est là que se situe toute la logique. On va définir les conditions, pour les différentes actions et retourner soit VoterInterface::ACCESS_DENIED si on interdit l'accès, ou VoterInterface::ACCESS_GRANTED si on l'autorise, ou enfin VoterInterface::ACCESS_ABSTAIN si le Voter doit déléguer la responsabilité de cette décision à la mécanique de sécurité.

Voici notre classe SolutionVoter :

Déclarer le Voter en tant que service

Il faut ensuite déclarer le Voter en tant que service pour qu’il soit ajouté à l'ensemble sécurité de Symfony.

Utiliser isGranted / is_granted

Voici comment utiliser le Voter dans un controller pour tester si l’on peut éditer la Solution :

La valeur de retour de isGranted dépend de celle de la méthode vote() de notre classe SolutionVoter.

Voici comment on peut l’utiliser en Twig, pour par exemple ne pas afficher un bouton « Editer » si is_granted retourne false (Même principe que la méthode PHP)

Pour aller plus loin