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

Symfony 2 : Comment vérifier le rôle d'un utilisateur en respectant la hiérarchie des rôles.
14 Mars 2015


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]

Pour cet exemple, nous utiliserons le système de rôle du célèbre bundle FOS User Bundle.

 

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 utilisateur qui ne nous appartient pas 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

Symfony2 propose un service pour gérer la hiérarchie des rôles :

$this->container->get('security.role_hierarchy')

Ce service propose une fonction pour récupérer les rôles hérités à partir d'un rôle donné :

$role = new \Symfony\Component\Security\Core\Role\Role('ROLE_ADMIN');
$all_roles = $this->get('security.role_hierarchy')->getReachableRoles($role);

Ici, $all_roles contient tous les rôles hérités du ROLE_ADMIN (ROLE_ADMIN inclus).

Il nous reste plus qu'à vérifier que le rôle qu'on recherche est dans au moins une dépendance des rôles du compte utilisateur.

 

Créer un service pour vérifier le role d'un utilisateur

Créez le service :

<?php

namespace Mon\PropreBundle\Services;


use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;

class RoleService
{
    private $roleHierarchy;

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

    /**
     * isGranted
     *
     * @param string $role
     * @param $user
     * @return bool
     */
    public function isGranted($role, $user) {

        $role = new Role($role);

        foreach($user->getRoles() as $userRole) {
            if (in_array($role, $this->roleHierarchy->getReachableRoles(array(new Role($userRole)))))
                return true;
        }

        return false;
    }
}

 

Activez le service :

services:
    mon_propre_bundle.service.role:
        class: Mon\PropreBundle\Services\RoleService
        arguments: [@security.role_hierarchy]

 

Il ne vous reste plus qu'à l'utiliser :

$this->get('mon_propre_bundle.service.role')->isGranted('ROLE_ADMIN', $user)

 

Commentaires

Rémi POIGNON admin
28 Août 2017 08:52

@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.

lionel
24 Août 2017 18:15

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 !!

pico34
14 Avril 2016 10:46

tip top merci !

Sébastien
31 Mars 2016 12:37

Bravo pour la clarté des explications !
On peut aussi utiliser cette méthode: http://stackoverflow.com/questions/11288293/how-to-use-the-accessdecisionmanager-in-symfony2-for-authorization-of-arbitrary/22380765#22380765

adrieng
05 Février 2016 12:07

Nice tip ;)

misterhobbes44
02 Novembre 2015 01:41

Super !! un article bien utile et clair.

Merci

Leenzur
17 Septembre 2015 09:29

C'est parfait ! Merci pour l'astuce !

reg
22 Août 2015 22:27

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

mickaelandrieu
05 Mai 2015 00:05

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

Thank you for the tip