如何在Symfony2中实现角色/资源ACL
我对Symfony2中实现访问控制列表的方式感到有点不安。如何在Symfony2中实现角色/资源ACL
在Zend框架(版本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中使用角色的规避方式?
以后要回答这个问题来,这是很容易解决的。
解决方案是混合角色和资源的概念。
我们假设一个role
表,一个resource
表和和role_resource
多对多关系被定义。
用户存储在user
表中。
这里有相应的学说实体:
用户:
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;
// ...
}
所以,现在的解决方案是实现了的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;
}
}
这样,归因于当前用户资源可以检查这种方式(考虑到有资源,其名称是):
$this->get('security.context')->isGranted('ROLE_ARTICLE_WRITE')
我认为这会回答你的问题。
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);