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 ton 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 tu souhaite 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 rôles. 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