如何在数据库级别动态处理 Symfony2 中的角色|权限:对它们的 CRUD 操作
How to dynamic handle roles|permissions in Symfony2 at database level: CRUD operations over them
我在 Symfony 2.8 项目中工作,我对 users/groups/roles|权限有疑问。有几种方法可以处理用户和组,例如 SonataUser on top of SonataAdmin and lately EasyAdmin 但它们都缺乏 ROLE|权限管理,这正是我的疑问:处理它们的正确方法是什么?是的,我知道我需要将它们写在 security.yml
但我不知道我是否可以将它们存储在数据库(某处)中然后从那里读取。我对此进行了研究,发现了 ACL、选民等,但研究并没有让我头脑清醒,而是让我很困惑,所以我需要这里的人的一些推动。那么:
- 你会如何处理?
- 有代码级别的例子吗? (我更喜欢看文字以外的东西来理解重点)
- ROLES 等同于权限吗?
更新:改进问题
我想要的是 users
和 roles
以及 groups
和 roles
之间的 ManyToMany
关系。我认为 SonataUserBundle
处理这个问题是通过在 user
table 中创建一个列 roles
并为每个用户分配很多角色,如果我是没错,但是如果我想创建尽可能多的角色而不将它们分配给用户,然后向用户甚至组添加许多角色怎么办?
你会怎么做?
您可以随时随地在 FOSUserBundle
中添加新角色。您最初无需将其添加到 security.yml
文件中。
为此,您可以这样做:
$user = new User();
$user->addRole('ROLE_NEWUSER'); //Role Name should begin with 'ROLE_'
或者在你的控制器中你可以获得当前或任何用户
$this->getUser();
$user->addRole('ROLE_NEWUSER'); //Role Name should begin with 'ROLE_'
这回答了你的第一部分和第二部分。
对于第三部分,角色可以用作权限。我之前已经实现了一个结构,在该结构中,我根据用户角色限制对页面的访问,同时也限制了他们可以根据他们的角色更改哪些数据。
UPDATE 我为此实现了一个 Event Listener,它将监听所有称为 onKernelRequest
的内核请求。我已经在 SQL 端完成了部分访问管理,因为我的角色也存储在 SQL 端,但可以在服务器端执行相同的操作。我的事件监听器看起来像这样:(这是我所拥有的精简版)
class TokenListener
{
protected $em;
protected $token_storage;
protected $templating;
protected $router;
protected $resolver;
public function __construct($em,TokenStorageInterface $token_storage, TwigEngine $templating, Router $router, ControllerResolver $resolver)
{
$this->em = $em;
$this->token_storage = $token_storage;
$this->templating = $templating;
$this->router = $router;
$this->resolver = $resolver;
}
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
$route = $request->attributes->get('_route');
$routeArr = array('fos_js_routing_js', 'fos_user_security_login', '_wdt'); //These are excluded routes. These are always allowed. Required for login page
if(!is_int(array_search($route, $routeArr)) && false)
{
$userRoles = $this->token_storage->getToken()->getUser()->getRoles();
if(!in_array('ROLE_NEWUSER', $userRoles))
{
$event->setResponse(new RedirectResponse($this->router->generate('user_management_unauthorized_user', array())));
}
}
}
}
我的services.yml看起来像这样
services:
app.tokens.action_listener:
class: EventListenerBundle\EventListener\TokenListener
arguments:
entityManager: "@doctrine.orm.entity_manager"
token_storage: "@security.token_storage"
templating: "@templating"
router: "@router"
resolver: "@controller_resolver"
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
UPDATE 要回答问题的更新部分,您可以做的是拥有另一个 roles
实体,您可以提前填充您想要的角色,然后与原来的User
table是一对多的关系。然后,您可以使用 prePersist or preUpdate Doctrine Lifecycle Events
之类的东西来检查添加新角色时角色实体中是否已经存在。那应该可以准确地解决您的问题。不过,所有这些都需要进行一些调整。没有直接的方法可以做到这一点。
这取决于你想如何实现它。
一种方法:
实现UserProviderInterface
到loadByUsername
(这是你加载角色和权限的地方)一个UserInterface
(你的User
)的实现。
然后实施 VoterInterface
。将此注册为带有 security.voter
标记的服务,并在 security.yml 中将其指定为提供商。覆盖 vote
函数以评估您从 TokenInterface
加载的权限(可能还有角色),这是该函数的第一个参数。
我在 Symfony 2.8 项目中工作,我对 users/groups/roles|权限有疑问。有几种方法可以处理用户和组,例如 SonataUser on top of SonataAdmin and lately EasyAdmin 但它们都缺乏 ROLE|权限管理,这正是我的疑问:处理它们的正确方法是什么?是的,我知道我需要将它们写在 security.yml
但我不知道我是否可以将它们存储在数据库(某处)中然后从那里读取。我对此进行了研究,发现了 ACL、选民等,但研究并没有让我头脑清醒,而是让我很困惑,所以我需要这里的人的一些推动。那么:
- 你会如何处理?
- 有代码级别的例子吗? (我更喜欢看文字以外的东西来理解重点)
- ROLES 等同于权限吗?
更新:改进问题
我想要的是 users
和 roles
以及 groups
和 roles
之间的 ManyToMany
关系。我认为 SonataUserBundle
处理这个问题是通过在 user
table 中创建一个列 roles
并为每个用户分配很多角色,如果我是没错,但是如果我想创建尽可能多的角色而不将它们分配给用户,然后向用户甚至组添加许多角色怎么办?
你会怎么做?
您可以随时随地在 FOSUserBundle
中添加新角色。您最初无需将其添加到 security.yml
文件中。
为此,您可以这样做:
$user = new User();
$user->addRole('ROLE_NEWUSER'); //Role Name should begin with 'ROLE_'
或者在你的控制器中你可以获得当前或任何用户
$this->getUser();
$user->addRole('ROLE_NEWUSER'); //Role Name should begin with 'ROLE_'
这回答了你的第一部分和第二部分。
对于第三部分,角色可以用作权限。我之前已经实现了一个结构,在该结构中,我根据用户角色限制对页面的访问,同时也限制了他们可以根据他们的角色更改哪些数据。
UPDATE 我为此实现了一个 Event Listener,它将监听所有称为 onKernelRequest
的内核请求。我已经在 SQL 端完成了部分访问管理,因为我的角色也存储在 SQL 端,但可以在服务器端执行相同的操作。我的事件监听器看起来像这样:(这是我所拥有的精简版)
class TokenListener
{
protected $em;
protected $token_storage;
protected $templating;
protected $router;
protected $resolver;
public function __construct($em,TokenStorageInterface $token_storage, TwigEngine $templating, Router $router, ControllerResolver $resolver)
{
$this->em = $em;
$this->token_storage = $token_storage;
$this->templating = $templating;
$this->router = $router;
$this->resolver = $resolver;
}
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
$route = $request->attributes->get('_route');
$routeArr = array('fos_js_routing_js', 'fos_user_security_login', '_wdt'); //These are excluded routes. These are always allowed. Required for login page
if(!is_int(array_search($route, $routeArr)) && false)
{
$userRoles = $this->token_storage->getToken()->getUser()->getRoles();
if(!in_array('ROLE_NEWUSER', $userRoles))
{
$event->setResponse(new RedirectResponse($this->router->generate('user_management_unauthorized_user', array())));
}
}
}
}
我的services.yml看起来像这样
services:
app.tokens.action_listener:
class: EventListenerBundle\EventListener\TokenListener
arguments:
entityManager: "@doctrine.orm.entity_manager"
token_storage: "@security.token_storage"
templating: "@templating"
router: "@router"
resolver: "@controller_resolver"
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
UPDATE 要回答问题的更新部分,您可以做的是拥有另一个 roles
实体,您可以提前填充您想要的角色,然后与原来的User
table是一对多的关系。然后,您可以使用 prePersist or preUpdate Doctrine Lifecycle Events
之类的东西来检查添加新角色时角色实体中是否已经存在。那应该可以准确地解决您的问题。不过,所有这些都需要进行一些调整。没有直接的方法可以做到这一点。
这取决于你想如何实现它。
一种方法:
实现UserProviderInterface
到loadByUsername
(这是你加载角色和权限的地方)一个UserInterface
(你的User
)的实现。
然后实施 VoterInterface
。将此注册为带有 security.voter
标记的服务,并在 security.yml 中将其指定为提供商。覆盖 vote
函数以评估您从 TokenInterface
加载的权限(可能还有角色),这是该函数的第一个参数。