【问题标题】:How to implement role / resources ACL in Symfony2Symfony2中如何实现角色/资源ACL
【发布时间】:2012-12-21 02:15:54
【问题描述】:

我对 Symfony2 中实现访问控制列表的方式感到有些不安。

在 Zend Framework(第 1 版和第 2 版)中,定义了一个资源列表和一个角色列表,并且每个角色都被分配了一个允许使用的资源子集使用权。因此,资源和角色是 ACL 实现的主要词汇,而 Symfony2 中并非如此,只有角色规则。

在旧版应用程序数据库中,我有表定义角色列表、资源列表和每个角色的允许资源列表(多对多关系)。每个用户都被分配了一个角色(管理员、超级管理员、编辑等)。

我需要在 Symfony2 应用程序中使用这个数据库。 我的资源如下所示:ARTICLE_EDIT、ARTICLE_WRITE、COMMENT_EDIT 等。

我在 Symfony 中的 User 实体实现了 Symfony\Component\Security\Core\User\UserInterface 接口,因此有一个 getRoles) 方法。

我打算用这种方法来定义允许的资源,也就是说我使用角色作为资源(我的意思是Zend Framework中所谓的资源在这里称为角色)。

您确认我应该使用这种方法吗?

这意味着我不再关心每个用户的角色(管理员、编辑...),而只关心其资源。

然后我会在我的控制器中使用$this->get('security.context')->isGranted('ROLE_ARTICLE_WRITE')

这是正确的方法吗?难道不是在 Symfony 中使用角色的一种规避方法吗?

【问题讨论】:

    标签: symfony acl


    【解决方案1】:

    多年后回答这个问题,很容易解决。

    解决方案是混合角色和资源的概念。

    假设定义了一个role 表、一个resource 表和role_resource 多对多关系。

    用户存储在user 表中。

    以下是对应的 Doctrine 实体:

    用户:

    use Symfony\Component\Security\Core\User\UserInterface;
    
    class User implements UserInterface
    {
        /**
         * @Id @Column(type="integer")
         * @GeneratedValue
         */
        private $id;
    
        /**
         * @ManyToOne(targetEntity="Role")
         * @JoinColumn(name="role_id", referencedColumnName="id")
         **/
        private $role;
    
        // ...
    }
    

    角色:

    class Role
    {
        /**
         * @Id @Column(type="integer")
         * @GeneratedValue
         */
        private $id;
    
        /** @Column(type="string") */
        private $name;
    
        /**
         * @ManyToMany(targetEntity="Resource")
         * @JoinTable(name="role_resource",
         *      joinColumns={@JoinColumn(name="role_id", referencedColumnName="id")},
         *      inverseJoinColumns={@JoinColumn(name="resource_id", referencedColumnName="id")}
         *      )
         **/
        private $resources;
    
        // ...
    }
    

    资源:

    class Resource
    {
        /**
         * @Id @Column(type="integer")
         * @GeneratedValue
         */
        private $id;
    
        /** @Column(type="string") */
        private $name;
    
        // ...
    }
    

    所以现在的解决方案是这样实现UserInterfacegetRoles

    use Symfony\Component\Security\Core\User\UserInterface;
    use Symfony\Component\Security\Core\Role\Role;
    
    class User implements UserInterface
    {
        // ...
    
        /**
         * @var Role[]
         **/
        private $roles;
    
        /**
         * {@inheritDoc}
         */
        public function getRoles()
        {
            if (isset($this->roles)) {
                return $this->roles;
            }
    
            $this->roles = array();
    
            $userRole = $this->getRole();
    
            $resources = $userRole->getResources();
    
            foreach ($resources as $resource) {
                $this->roles[] = new Role('ROLE_' . $resource);
            }
    
            return $this->roles;
        }
    
    }
    

    这样可以查看归属于当前用户的资源(假设有一个资源名称为ARTICLE_WRITE):

    $this->get('security.context')->isGranted('ROLE_ARTICLE_WRITE')
    

    【讨论】:

      【解决方案2】:

      我想这会回答你的问题。

      http://symfony.com/doc/current/cookbook/security/acl.html http://symfony.com/doc/current/cookbook/security/acl_advanced.html

      $builder = new MaskBuilder();
      $builder
      ->add('view')
      ->add('edit')
      ->add('delete')
      ->add('undelete');
      $mask = $builder->get(); // int(29)
      
      $identity = new UserSecurityIdentity('johannes', 'Acme\UserBundle\Entity\User');
      $acl->insertObjectAce($identity, $mask);
      

      【讨论】:

        猜你喜欢
        • 2016-10-11
        • 2016-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-08
        • 1970-01-01
        • 2014-02-26
        • 1970-01-01
        相关资源
        最近更新 更多