Cet article est écrit pour la version 5 de Symfony mais à priori il devrait aussi fonctionner au moins pour les version 3 et 4 du framework
Sous Symfony la fonction permettant de savoir si l’utilisateur en train de parcourir l’application possède un certain rôle est « isGranted » elle est directement disponible à l’utilisation dans les templates twig, via les annotations, depuis le services « Symfony\Component\Security\Core\Security » ou directement dans les controllers de la façon suivante :
//l'utilisateur à les droits admin
}
Par contre il n’existe pas de façon directe d’utiliser cette fonction sur un objet utilisateur différent de l’utilisateur courant.
Étant donnée le fonctionnement des rôles sous symfony, qui peuvent hériter des droits d’un autre rôle il ne faut pas utiliser un simple
En effet dans ce cas, si un utilisateur à le rôle ‘ROLE_SUPERADMIN’ qui hérite de ‘ROLE_ADMIN’ le contrôle ci dessus ne lui accordera pas les droits.
On imagine ici la hiérarchie des rôle suivante :
ROLE_ADMIN: ROLE_USER
ROLE_SUPERADMIN: ROLE_ADMIN
Pour résoudre ce problème, nous allons créer la fonction « isGranted » prenant en paramètre un utilisateur et le rôle à vérifier dans un service « Securizer », je vous le livre directement prêt à utiliser :
use App\Entity\User;//l'entité user de notre aplication
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
class Securizer {
private $accessDecisionManager;
public function __construct(AccessDecisionManagerInterface $accessDecisionManager) {
$this->accessDecisionManager = $accessDecisionManager;
}
public function isGranted(User $user, $attribute, $object = null) {
$token = new UsernamePasswordToken($user, 'none', 'none', $user->getRoles());
return ($this->accessDecisionManager->decide($token, [$attribute], $object));
}
}
Grâce à la configuration par défaut de Symfony on peux sans plus attendre utiliser ce service dans notre application et vérifier correctement les droits de n’importe quel utilisateur en prenant bien en compte la hiérarchie des rôles configuré dans le fichier « security.yaml ». Par exemple dans un controller on peux désormais faire :
//récupération d'un utilisateur $user de n'importe quelle manière, par exemple via une requête en base de données.
//verification des droits
if($securizer->isGranted($user, 'ROLE_ADMIN')){
//l'utilisateur à les droits admin
}
}
Il y’a sans doute de nombreux cas ou ce besoin de contrôle des rôles sur un utilisateur autre que celui connecté se fait sentir (d’où la mise en place de cette fonctionnalité sous la forme d’un service), particulièrement lors de l’utilisation de Voters pour sécuriser la gestion des droits de l’application. Dans mon cas j’ai d’abord eu besoin de cette fonctionnalité pour contrôler finement la possibilité de se « connecter en tant que » (switch_user) pour mes administrateurs.
Voir les détails dans le prochain article : Limiter la possibilité de « switch_user » en fonction du rôle de l’utilisateur cible.
Bonjour,
Je souhaiterais utiliser votre code cependant j’ai l’erreur suivante :
« Catchable Fatal Error: Argument 1 passed to App\UserBundle\Service\Securizer::__construct() must implement interface Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface, none given, called in […] »
Ce qui est logique puisque je ne lui donne aucun argument:
services:
App.user.securizer:
class: App\UserBundle\Service\Securizer
arguments: []*
Quel argument dois-je fournir pour que cela puisse fonctionner ?
D’avance merci
public function myFunction(SecurizerSecurizer $securizer): Response {
}