Symfony2检查子实体的ACL

时间:2013-01-09 23:42:59

标签: symfony entity parent-child acl

我想在列出父项时检查几个子实体的acl条目。

这是当前的设置:

Gallery (parent)
    Gallerycategory (child)
    Gallerylanguage (child)
  • 每个用户组都有自己的角色。
  • 在创建Gallerycategory或Gallerylanguage时,我会列出所有要访问此实体的组。
  • 选中后,组会在ACL中获取Gallerycategory -> ROLE_(Usergroup)关系的VIEW条目。

现在,当我想列出我的画廊时,只应显示允许的Gallerycategory或Gallerylanguage的条目。

最好的方法是什么?进入存储库并检查当前用户?

2 个答案:

答案 0 :(得分:0)

我想我想通了。

首先,我创建了一个名为 AclChildEntityInterface 的新界面。 很简单:

interface AclChildEntityInterface{ 
    public function getAclChildren(); 
}

我想要检查子ACL / ACE的每个实体都实现它并返回一个函数数组来让孩子参与其中。

class Gallery implements AclChildEntityInterface
{
    public function getAclChildren(){
        return array(
            'mediacategories' => 'getMediacategories',
            'medialanguages' => 'getMedialanguages',
        );
    }
}

注意:数组值必须作为当前实体类中的函数存在。

之后我创建了一个扩展Symfony\Component\Security\Acl\Voter\AclVoter的新AclVoter:

Class几乎相同,我juste改变了

的投票功能中的行为

catch (AclNotFoundException $noAcl)

use Symfony\Component\Security\Acl\Voter\AclVoter as BaseVoter;
...
use Develth\Prodcut\GalleryBundle\Entity\AclChildEntityInterface;

class MediaAclVoter extends BaseVoter
{
    ...
    public function vote(TokenInterface $token, $object, array $attributes)
    {
        ...
        } catch (AclNotFoundException $noAcl) {
            if (null !== $this->logger) {
                $this->logger->debug('No ACL found for the object identity. Voting to deny access.');
            }

            // Check if entity has childs to check
            if($object instanceof AclChildEntityInterface){
                $entityChilds = $object->getAclChildren();
                foreach ($entityChilds as $child) {
                    $childEntites = call_user_func( array($object,$child) );
                    foreach ($childEntites as $childEntity) {
                        $mapping =  $childEntity->getName();
                        $oid = $this->objectIdentityRetrievalStrategy->getObjectIdentity($childEntity);
                        try{
                            $acl = $this->aclProvider->findAcl($oid, $sids);
                            if($acl->isGranted($masks, $sids, false)){
                                // Has permission to view. show it. 
                                return self::ACCESS_GRANTED;
                            }
                        }catch(AclNotFoundException $noAcl){
                            // No ACL for this entity. Ignore
                        }catch(NoAceFoundException $noAce){
                            // No ACE for this entity. Ignore because other could have.
                        }
                    }
                }
            }

            return self::ACCESS_DENIED;
        } catch (NoAceFoundException $noAce) {
           ...

}    

这里发生了什么?

如果找不到当前实体的ACL,它会检查它是否是先前创建的AclChildEntityInterface的实例。如果找到ACE,它会检查每个childAcl并返回ACCESS_GRANTED

但仍有一些我不喜欢的东西,我认为可以改进。

在实现AclChildEntityInterface的Entity类中,我想做类似的事情:

public function getAclChildren(){
    return array(
        'mediacategories' => $this->mediacategories,
        'medialanguages' => $this->medialanguages,
    );
 }

或关于获取方法。

但是,如果我想访问选民中的那些,我总是以主实体媒体作为所有者获得PersistentCollection,因此我无法直接访问这些。这就是为什么我使用call_user_funk

我感谢你的改进!

答案 1 :(得分:0)

我刚刚根据@develth所描述的方法发布了一个解决确切问题的Symfony软件包。

https://github.com/GoDisco/AclTreeBundle

AclTree Bundle 允许您在实体之间为ACL权限创建层次结构关系。