Symfony2自定义选民角色层次结构

Mat*_*att 4 symfony

我正在尝试创建一个自定义选民来检查实体对特定操作的访问权限.所以这个逻辑很好.但是,如果用户是该实体的"所有者",或者他们是管理员,那么我有一些允许的操作.

但是,我不能只检查用户的角色,因为我正在查看角色层次结构.文档中的示例仅用于此in_array,但这不起作用(http://symfony.com/doc/current/best_practices/security.html)

我的选民是这样的(为了清晰起见缩短了).我已经尝试注入安全上下文(或2.6中的AuthorizationCheckerInterface),但由于这是一个选民,因此它具有循环依赖性.

<?php
// ...
class ApplicationVoter extends AbstractVoter
{
    const VIEW = 'view';

    /**
     * @var AuthorizationCheckerInterface 
     */
    private $security;

    /*public function __construct(AuthorizationCheckerInterface $security)
    {
        $this->security = $security;
    }*/

    /**
     * {@inheritdoc}
     */
    protected function getSupportedAttributes()
    {
        return array(
            self::VIEW
        );
    }

    /**
     * {@inheritdoc}
     */
    protected function getSupportedClasses()
    {
        return array('Study\MainBundle\Entity\Application');
    }

    /**
     * {@inheritdoc}
     */
    protected function isGranted($attribute, $application, $user = null)
    {
        if (!$user instanceof UserInterface) {
            return false;
        }

        if ($attribute === self::VIEW) {
            return $this->canView($application, $user);
        }

        return false;
    }

    /**
     * Can view own application if not deleted
     * Admin can view if submitted
     * 
     * @param \Study\MainBundle\Entity\Application $application
     * @param \Study\MainBundle\Entity\User $user
     * 
     * @return boolean
     */
    protected function canView(Application $application, User $user)
    {
        return ($application->isOwner($user) && !$application->isDeleted())
            || (!$application->isHiddenToAdmin() && $this->security->isGranted('ROLE_ADMIN_RO'));
    }
}
Run Code Online (Sandbox Code Playgroud)

我想在这里使用内置的RoleHiearchyVoter,但这是一个非公共服务.这有什么解决方案吗?如果可能的话,我想避免重复框架代码或使我的角色比字符串更复杂.

编辑:注入整个容器工作,但不是我理想的解决方案.这是我从选民访问内置层次结构的唯一方法吗?

Cer*_*rad 9

有一个名为security.role_hierarchy的服务,它包含您需要的信息.它基本上是安全上下文检查角色的方式.需要几行包装代码,但这并不算太糟糕.

# Need this because the service is not public
# http://symfony.com/doc/current/components/dependency_injection/advanced.html
cerad_core__role_hierarchy:
    alias: security.role_hierarchy

cerad_game__game_official__voter:
    class:  Cerad\Bundle\GameBundle\Action\GameOfficial\GameOfficialVoter
    public: false
    arguments:
      - '@cerad_core__role_hierarchy'
    tags:
       - { name: security.voter } 
Run Code Online (Sandbox Code Playgroud)

选民类:

class GameOfficialVoter implements VoterInterface
{    
    public function __construct($roleHierarchy)
    {  
        $this->roleHierarchy = $roleHierarchy;
    }

    protected function hasRole($token,$targetRole)
    {
        $reachableRoles = $this->roleHierarchy->getReachableRoles($token->getRoles());
        foreach($reachableRoles as $role)
        {
            if ($role->getRole() == $targetRole) return true;
        }
        return false;
    }

    protected function canViewOfficialName($official,$token)
    {    
         // Pending is the only one protected against for now
         if ($official->getAssignState() != 'Pending') return $this->accessGranted;

         // Assignors can always see
         if ($this->hasRole($token,'ROLE_ASSIGNOR')) return $this->accessGranted;

         return $this->accessDenied;
    }
}
Run Code Online (Sandbox Code Playgroud)