Я создал избирателя, где мне нужно вызвать is_granted для пользователя.
Когда я ввожу услугу security.authorization_checker у своего избирателя, я получаю следующую ошибку
ServiceCircularReferenceException в CheckCircularReferencesPass.php строка 69: обнаружена циклическая ссылка для службы «manager_voter», путь: «manager_voter -> security.authorization_checker -> security.access.decision_manager -> manager_voter».
Нет ли альтернативы инъекции всего контейнера? Это нормально?
РЕДАКТИРОВАТЬ:
Я звоню избирателю от контроллера:
if (false === $this->get('security.authorization_checker')->isGranted('manage', $associate)) { throw new AccessDeniedException('Unauthorised access!'); }
В этом избирателе мне нужно проверить роли пользователя:
if ($this->container->get('security.authorization_checker')->isGranted('ROLE_COMPANY_MANAGER')) { return true; }
Это, конечно, приводит к циклу. Как не получить этот цикл? Вызов $ user-> getRoles на пользователя не будет учитывать иерархию ролей, если я не ошибаюсь.
Поэтому я нашел ответ благодаря @Cerad:
Точность: вы не можете расширить класс abstractVoter, потому что вам нужен доступ к токену. Просто реализуйте тот же интерфейс, который реализует абстрактный избиратель.
Предложение Cerad: Symfony2 Пользовательская иерархия роли избирателя
Мой :
<?php namespace AppBundle\Security\Voter; use AppBundle\Entity\User\Associate; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; use Symfony\Component\Security\Core\Role\RoleHierarchy; use Symfony\Component\Security\Core\User\UserInterface; class ManagerVoter implements VoterInterface { const SELECT_ASSOCIATES = 'select_associates'; private $roleHierarchy; public function __construct(RoleHierarchy $roleHierarchy) { $this->roleHierarchy = $roleHierarchy; } protected function hasRole(TokenInterface $token, $targetRole) { $reachableRoles = $this->roleHierarchy->getReachableRoles($token->getRoles()); foreach($reachableRoles as $role) { if ($role->getRole() == $targetRole) return true; } return false; } protected function getSupportedClasses() { return array( 'AppBundle\Entity\User\Associate', ); } protected function getSupportedAttributes() { return array(self::SELECT_ASSOCIATES); } /** * Iteratively check all given attributes by calling isGranted * * This method terminates as soon as it is able to return ACCESS_GRANTED * If at least one attribute is supported, but access not granted, then ACCESS_DENIED is returned * Otherwise it will return ACCESS_ABSTAIN * * @param TokenInterface $token A TokenInterface instance * @param object $object The object to secure * @param array $attributes An array of attributes associated with the method being invoked * * @return int either ACCESS_GRANTED, ACCESS_ABSTAIN, or ACCESS_DENIED */ public function vote(TokenInterface $token, $object, array $attributes) { if (!$object || !$this->supportsClass(get_class($object))) { return self::ACCESS_ABSTAIN; } // abstain vote by default in case none of the attributes are supported $vote = self::ACCESS_ABSTAIN; foreach ($attributes as $attribute) { if (!$this->supportsAttribute($attribute)) { continue; } // as soon as at least one attribute is supported, default is to deny access $vote = self::ACCESS_DENIED; if ($this->isGranted($attribute, $object, $token)) { // grant access as soon as at least one voter returns a positive response return self::ACCESS_GRANTED; } } return $vote; } /** * Perform a single access check operation on a given attribute, object and (optionally) user * It is safe to assume that $attribute and $object's class pass supportsAttribute/supportsClass * $user can be one of the following: * a UserInterface object (fully authenticated user) * a string (anonymously authenticated user) * * @param string $attribute * @param object $object * @param $token * @internal param string|UserInterface $user * * @return bool */ protected function isGranted($attribute, $object, TokenInterface $token) { $user = $token->getUser(); /** @var $object Associate */ $associateRoles = $object->getRoles(); // make sure there is a user object (ie that the user is logged in) if (!$user instanceof UserInterface) { return false; } // if ($this->hasRole($token, 'ROLE_ADMIN')) // { // return true; // } if ($attribute == self::SELECT_ASSOCIATES) { if (in_array('ROLE_COMPANY_STAFF',$associateRoles)) { if ($this->hasRole($token, 'ROLE_COMPANY_MANAGER')) { return true; } } elseif (in_array('ROLE_BOUTIQUE_STAFF',$associateRoles)) { if ($this->hasRole($token, 'ROLE_BOUTIQUE_MANAGER')) { return true; } } elseif (in_array('ROLE_SCHOOL_STAFF',$associateRoles)) { if ($this->hasRole($token, 'ROLE_PROFESSOR')) { return true; } } } return false; } /** * {@inheritdoc} */ public function supportsAttribute($attribute) { return in_array($attribute, $this->getSupportedAttributes()); } /** * {@inheritdoc} */ public function supportsClass($class) { foreach ($this->getSupportedClasses() as $supportedClass) { if ($supportedClass === $class || is_subclass_of($class, $supportedClass)) { return true; } } return false; } }