Rémi

Symfony : Comment vérifier le rôle d’un utilisateur en respectant la hiérarchie des rôles

Vérifier rôle utilisateur hiérarchie

Imaginons une application dans laquelle on retrouve les rôles suivants :

  • ROLE_SUPER_ADMIN
  • ROLE_ADMIN
  • ROLE_CLIENT
  • ROLE_USER

Ainsi que cette hiérarchie :

  • ROLE_SUPER_ADMIN a aussi le rôle ROLE_ADMIN qui a aussi le rôle ROLE_USER.
  • ROLE_CLIENT a aussi le rôle ROLE_USER.

Dans votre fichier security.yml, on le définirait ainsi :

role_hierarchy:
    ROLE_CLIENT:      ROLE_USER
    ROLE_ADMIN:       ROLE_USER
    ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN]

La problématique

Imaginons que vous souhaitiez vérifier qu’un utilisateur a bien le ROLE_ADMIN. Très facile :

$this->container->get('security.authorization_checker')->isGranted('ROLE_ADMIN')

Ok mais cette fonction permet de vérifier le rôle de l’utilisateur actuellement connecté qui fait la demande.

Maintenant, comment faire pour vérifier qu’un autre utilisateur a bien le ROLE_ADMIN ? (Exemple, afficher une liste d’utilisateurs en affichant si oui ou non il est admin).

On pense tout de suite à :

if ($user->hasRole('ROLE_ADMIN'))

Mais un utilisateur SUPER_ADMIN retournerai « false » à cette fonction car la fonction hasRole ne vérifie pas la hiérarchie des rôles.

C’est le même problème si l’on veut vérifier que l’utilisateur a bien le ROLE_USER alors qu’il est admin ou client.

Résolution du problème

On peut utiliser un service présent dans le core de Symfony dans un controller :

use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;

class UserController extends AbstractController {

    /**
     * @Route("/{user}", name="app_user_view", requirements={"user"="\d+"})
     */
    public function view(AccessDecisionManagerInterface $accessDecisionManager, User $user): Response {
       $token = new UsernamePasswordToken($user, 'none', 'none', $user->getRoles());
       if ($accessDecisionManager->decide($token, 'ROLE_ADMIN')) {
            // L'utilisateur $user a le rôle ROLE_ADMIN
       }
...

Le service AccessDecisionManager permet de vérifier si l’utilisateur a bien les droits tout en vérifiant la hiérarchie des roles. Ce service permet aussi de vérifier les droits selon des règles spécifiques définies par les Voter.

Créer un service dédié à la vérification des droits

<?php

namespace App\Services;


use App\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;

class GrantedService
{
    private $accessDecisionManager;

    /**
     * Constructor
     *
     * @param AccessDecisionManagerInterface $accessDecisionManager
     */
    public function __construct(AccessDecisionManagerInterface $accessDecisionManager) {
        $this->accessDecisionManager = $accessDecisionManager;
    }

    public function isGranted(User $user, $attributes, $object = null) {
        if (!is_array($attributes))
            $attributes = [$attributes];

        $token = new UsernamePasswordToken($user, 'none', 'none', $user->getRoles());

        return ($this->accessDecisionManager->decide($token, $attributes, $object));
    }
}

C’est tout, cette fonction fonctionne maintenant exactement comme la fonction isGranted disponible de base dans les controller sauf qu’il faut spécifier l’utilisateur à checker :

class UserController extends AbstractController {

    /**
     * @Route("/{user}", name="app_user_view", requirements={"user"="\d+"})
     */
    public function view(GrantedService $grantedService, User $user): Response {
       if ($grantedService->isGranted($user 'ROLE_ADMIN')) {
            // L'utilisateur $user a le rôle ROLE_ADMIN
       }
...

C’est tout pour aujourd’hui ! N’hésitez pas à poser vos questions dans les commentaires et à partager cet article ! Merci

Partagez cette page

Comment (11)

  • Avatar
    mickaelandrieu| 5 mai 2015

    This sounds like FOSUserBundle provide this feature: http://stackoverflow.com/a/24078528

    Thank you for the tip

  • Avatar
    reg| 22 août 2015

    Pile ce que je cherchais.
    Explication claire : merci bcp!!

  • Avatar
    Leenzur| 17 septembre 2015

    C’est parfait ! Merci pour l’astuce !

  • Avatar
    misterhobbes44| 2 novembre 2015

    Super !! un article bien utile et clair.

    Merci

  • Avatar
    adrieng| 5 février 2016

    Nice tip 😉

  • Avatar
    pico34| 14 avril 2016

    tip top merci !

  • Avatar
    lionel| 24 août 2017

    Pas besoin d’un service pour si peut :

    if( $user->isGranted(‘ROLE_QUE_TU_VEUX’) ) echo ‘Blaaaa !’;

    Avant de créer un service, assurez-vous qu’il n’y a vraiment pas moyen de faire plus simple !!

    • Rémi
      Rémi| 28 août 2017

      @lionel, par la méthode que vous utilisez, vous ne pouvez pas vérifier la hiérarchie des rôles, ce qui est le but de mon article. D’où l’utilisation d’un service.

    • Avatar
      Barbapapa| 3 novembre 2019

      UserInterface ne fourni pas de méthode isGranted(). Cette méthode est éventuellement fournie par AbstractController, mais utilise toujours l’utilisateur connecté, ce qui ne résout pas le problème.
      La création d’un service à donc toute son utilité.
      Merci pour cet article très utile.

  • Avatar
    vincent| 2 novembre 2019

    Bonjour à tous,
    Je suis dév sur symfony est il y a une autre méthode qui me semble tout aussi simple : les voters
    php bin/console make:voter

  • Laisser un commentaire

    Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

    Plus dans Développement web
    Configuration des logs Monolog
    Symfony : Configuration des logs Monolog

    Symfony utilise Monolog pour gérer les logs. Les logs te permette de garder une trace de ce qui se passe...

    Fermer