6

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

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

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

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

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

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

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

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

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

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

4

2 回答 2

2

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

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

假设定义了一个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;

    // ...
}

getRoles所以现在的解决方案是实现UserInterface这种方式:

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')
于 2014-10-27T15:26:54.907 回答
0

我想这会回答你的问题。

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);
于 2014-10-04T14:01:47.790 回答