首页 文章

Symfony2检查子实体的ACL

提问于
浏览
0

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

那是当前的设置:

Gallery (parent)
    Gallerycategory (child)
    Gallerylanguage (child)
  • 每个用户组都有自己的角色 .

  • 在创建Gallerycategory或Gallerylanguage时,我会列出所有要访问此实体的组 .

  • 选中时,组在ACL中获取 Gallerycategory -> ROLE_(Usergroup) 关系的VIEW条目 .

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

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

2 回答

  • 0

    我想我想通了 .

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

    interface AclChildEntityInterface{ 
        public function getAclChildren(); 
    }
    

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

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

    NOTE: 数组值必须作为当前实体类中的函数存在 .

    之后我创建了一个扩展 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 .

    But there are still some things i don´t like and i think it could be improved.

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

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

    或者关于获取方法 .

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

    我感谢你的改进!

  • 0

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

    https://github.com/GoDisco/AclTreeBundle

    AclTree Bundle 允许您在ACL实现的实体之间创建层次结构关系 .

相关问题