0

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

这就是当前的设置:

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

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

实现这一目标的最佳方法是什么?进入存储库并检查当前用户?

4

2 回答 2

0

我想我想通了。

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

interface AclChildEntityInterface{ 
    public function getAclChildren(); 
}

我要检查子 ACL / ACE 的每个实体都实现它并返回一个函数数组以获取子实体。

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

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

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

类几乎相同,我只是改变了投票功能中的行为

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 的实例。它让每个 childAcl 检查并返回一个ACCESS_GRANTED是否找到 ACE。

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

在实现的实体类中,AclChildEntityInterface我想做这样的事情:

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

或关于获取方法。

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

我感谢改进!

于 2013-01-10T14:13:17.917 回答
0

我刚刚发布了一个 Symfony 包,它基于 @develth 描述的方法论解决了确切的问题。

https://github.com/GoDisco/AclTreeBundle

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

于 2014-12-01T11:48:27.127 回答