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 (9)

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

  • 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