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

如何在Symfony2中实现角色/资源ACL,symfony,acl,Symfony,Acl,我对在Symfony2中实现访问控制列表的方式感到有点不安 在Zend框架(版本1和版本2)中,定义了资源列表和角色列表,并为每个角色分配了允许其访问的资源子集。因此,资源和角色是ACL实现的主要词汇表,而在Symfony2中则不是这样,在Symfony2中,只有角色起作用 在遗留应用程序数据库中,我有定义角色列表、资源列表和每个角色允许的资源列表(多对多关系)的表。每个用户都被分配了一个角色(管理员、超级管理员、编辑等) 我需要在Symfony2应用程序中使用此数据库。 我的资源是这样的:文章

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

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

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

我需要在Symfony2应用程序中使用此数据库。 我的资源是这样的:文章编辑、文章写作、评论编辑等等

Symfony中的My
User
实体实现了
Symfony\Component\Security\Core\User\UserInterface
接口,因此具有
getRoles)
方法

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

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

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

然后我会在我的控制器中使用
$this->get('security.context')->isgrated('ROLE\u ARTICLE\u WRITE')


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

我认为这将回答您的问题


多年后,要回答这个问题,这是很容易解决的

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

让我们假设定义了
角色
表、
资源
表和
角色资源
多对多关系

用户存储在
user
表中

以下是相应的条令实体:

用户:

角色:

资源:

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

    /** @Column(type="string") */
    private $name;

    // ...
}
因此,现在的解决方案是通过以下方式实现
UserInterface
getRoles

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\u WRITE
):

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;

    // ...
}
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;
    }

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