如何在Symfony2中实现角色/资源ACL



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

在Zend框架(版本1 &2),定义一个资源列表和一个角色列表,并为每个角色分配一个允许访问的资源子集。因此,资源和角色是ACL实现的主要词汇表,而在Symfony2中不是这样,在Symfony2中只有角色规则。

在遗留应用程序数据库中,我有定义角色列表的表,资源列表和每个角色允许的资源列表(多对多关系)。每个用户被分配一个角色(admin、超级admin、editor等)。

我需要在Symfony2应用程序中使用这个数据库。我的资源看起来像这样:ARTICLE_EDIT, ARTICLE_WRITE, COMMENT_EDIT等。

我在Symfony中的User实体实现了SymfonyComponentSecurityCoreUserUserInterface接口,因此有一个getRoles)方法。

我打算使用这个方法来定义允许的资源,这意味着我使用角色作为资源(我的意思是Zend框架中所谓的资源在这里被称为角色)。

你确定我应该用这个方法吗?

这意味着我不再关心每个用户的角色(admin, editor,…),而只关心它的资源。

我将使用$this->get('security.context')->isGranted('ROLE_ARTICLE_WRITE')在我的控制器。

这样做是正确的吗?这不是在Symfony中使用角色的一种规避方式吗?

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

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

假设有一个role表、一个resource表和一个role_resource多对多关系。

用户存储在user表中

以下是相应的Doctrine实体:

用户:

use SymfonyComponentSecurityCoreUserUserInterface;
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 SymfonyComponentSecurityCoreUserUserInterface;
use SymfonyComponentSecurityCoreRoleRole;
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')

我想这会回答你的问题。

http://symfony.com/doc/current/cookbook/security/acl.htmlhttp://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', 'AcmeUserBundleEntityUser');
$acl->insertObjectAce($identity, $mask);

最新更新