<?php
namespace App\Security;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Http\Event\SwitchUserEvent;
use Symfony\Component\Security\Http\SecurityEvents;
class SwitchUserSubscriber implements EventSubscriberInterface
{
private const ROLE_PRIORITY = [
'ROLE_SUPERADMIN' => 60,
'ROLE_ADMIN' => 50,
'ROLE_MANAGER' => 40,
'ROLE_SUPPORT_MASTER' => 35,
'ROLE_SUPPORT' => 30,
'ROLE_SECRETARIAT' => 20,
'ROLE_TEACHER' => 10,
'ROLE_USER' => 10,
'ROLE_EMAIL' => 10,
];
private TokenStorageInterface $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public static function getSubscribedEvents(): array
{
return [
SecurityEvents::SWITCH_USER => 'onSwitchUser',
];
}
public function onSwitchUser(SwitchUserEvent $event): void
{
// Ne pas bloquer le retour à son propre compte
if ($event->getRequest()->get('_switch_user') === '_exit') {
return;
}
$token = $this->tokenStorage->getToken();
if ($token === null) {
throw new AccessDeniedException();
}
$switcherLevel = $this->getMaxRoleLevel($token->getUser()->getRoles());
$targetLevel = $this->getMaxRoleLevel($event->getTargetUser()->getRoles());
if ($targetLevel >= $switcherLevel) {
throw new AccessDeniedException('Vous ne pouvez pas prendre le contrôle d\'un compte avec un niveau de permissions égal ou supérieur au vôtre.');
}
}
private function getMaxRoleLevel(array $roles): int
{
$max = 0;
foreach ($roles as $role) {
$max = max($max, self::ROLE_PRIORITY[$role] ?? 0);
}
return $max;
}
}