2014-12-06 55 views
4

我正在嘗試創建一個自定義選民來檢查實體訪問特定操作的訪問權限。所以這個邏輯工作正常。但是,如果用戶是該實體的「所有者」,或者他們是管理員,則我有一些允許的操作。Symfony2自定義選民角色層次

但是,我不能只檢查用戶的角色,因爲我正在查看角色層次結構。在這個文檔中的例子只是使用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')); 
    } 
} 

我想在這裏使用內置的RoleHiearchyVoter,但它是一個非公共服務。 有沒有解決這個問題的方法?我希望避免重複框架代碼,或者儘可能避免使用比字符串更復雜的角色。

編輯:注入整個容器的作品,但是不是我理想的解決方案。這是我可以從選民訪問內置層次結構的唯一方法嗎?

回答

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 } 

選民類:

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; 
    } 
} 
+1

我想我只是被愚蠢和假設'公共=「假」'這些服務意味着我無法將它們注入。我不知道爲什麼我沒有嘗試這個。 – Matt 2014-12-06 08:17:16

+0

@Matt - 我想知道爲什麼我在我的代碼中有一個別名。自從我看了它已經有一段時間了。如果不先創建別名,則無法訪問角色層次結構服務。我的答案已更新。複製後編輯的危險。 http://symfony.com/doc/current/components/dependency_injection/advanced.html – Cerad 2014-12-06 13:57:22

+0

它看起來像服務不公開,你可以注入它的services.yml/xml配置,但你不能從它容器直接。別名允許你直接從容器中獲取它('$ container-> get(...)')。我不需要使用別名通過配置注入服務。謝謝! – Matt 2014-12-08 02:35:41