2014-12-08 3 views
4

Я создал избирателя, где мне нужно вызвать is_granted для пользователя.symfony2 call is_granted в избирателе: как избежать бесконечного цикла?

При внутривенном введении службы security.authorization_checker в моем избирателе я получаю следующую ошибку

ServiceCircularReferenceException в CheckCircularReferencesPass.php линия 69: Циклическая ссылка обнаружено для обслуживания "manager_voter", пути: «manager_voter -> security.authorization_checker -> security.access.decision_manager -> manager_voter ".

Нет ли альтернативы инъекции всего контейнера? Это нормально?

EDIT:

Я зову избиратель от контроллера:

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 на пользователя не будет учитывать иерархию ролей, если я не ошибаюсь.

+0

может быть, вы также должны показать код, которая создает ошибку. –

+0

@AaronHall: код добавлен. Я не вижу, как вызвать is_granted без бесконечного цикла. –

+0

'if ($ this -> $ container-> get' это' '' в контейнере опечатка? –

ответ

0

Так я нашел ответ благодаря @Cerad:

Точность: вы не можете расширить класс abstractVoter причина вам нужен доступ к маркеру. Просто реализуйте тот же интерфейс, который реализует абстрактный избиратель.

Cerad предложение: Symfony2 Custom Voter Role Hierarchy

Mine:

<?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 (i.e. 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; 
    } 
}