[英]How to dynamic handle roles|permissions in Symfony2: restrict functions with dynamic roles
This post aims to be a kind of second part of this post so you may have to read it to understand this question. 这篇文章的目的是一种第二部分的这个职位,所以你可能要读得懂这个问题。 Having that info and the answer from previous post and also having found this useful UserBundle which help me as an example to illustrate possible relationship as
Many To Many
between roles
and users
I may ask: 拥有该信息和上一篇文章的答案,并且还发现了这个有用的UserBundle ,可以帮助我举例说明
roles
和users
之间可能存在的Many To Many
关系:
ROLES
? ROLES
? What I mean, for example I want to limit a existent function to role ROLE_NEWROLE
which has been created dynamically and therefore doesn't exists on the base code (original sources) then how do I restrict a existent function to that new role? 我的意思是,例如,我想将现有功能限制为已动态创建的
ROLE_NEWROLE
角色,因此在基础代码(原始源代码)上不存在,那么如何将现有功能限制为该新角色? Take the docs here as an example: 以此处的文档为例:
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
class PostController extends Controller
{
/**
* @Security("has_role('ROLE_ADMIN')")
*/
public function indexAction()
{
// ...
}
}
The code above presume that ROLE_ADMIN
is already declared somewhere and somehow but what if I want to add the new ROLE_NEWROLE
to that function through security component? 上面的代码假定
ROLE_ADMIN
已经在某处以某种方式声明,但是如果我想通过安全组件将新的ROLE_NEWROLE
添加到该函数中怎么办? Do I need to touch my code all the time? 我是否需要一直触摸我的代码? That isn't funny at all so I want to know your opinions about this topic.
这一点都不好笑,所以我想知道您对这个话题的看法。
As we talked about this before , you need to implement EventListener
which will listen to your onKernelRequest
. 正如我们之前讨论的那样,您需要实现
EventListener
,它将侦听onKernelRequest
。
In plain English, this means that all of your Controller Actions will execute onKernelRequest
first before giving access to the original controller. 用简单的英语来说,这意味着在授予对原始控制器的访问权限之前, 所有控制器动作将首先执行
onKernelRequest
。 So this way you won't have to write 这样您就不必写
/**
* @Security("has_role('ROLE_ADMIN')")
*/
in every controller action. 在每个控制器动作中。
Now, its upto you what you want to do in this method. 现在,取决于您要使用此方法执行的操作。 My approach was to make a table which associates a
ROLE
with a ROUTE
. 我的方法是制作一个将
ROLE
与ROUTE
关联的表。 This table will be comparatively big because you have to include all ROLES
you want to give access to all ROUTES
. 该表将相对较大,因为您必须包括要授予所有
ROUTES
访问权限的所有ROLES
。
The table structure can be something like this: 表结构可以是这样的:
ACCESSID ROLENAME ROUTENAME
1 ROLE_NEWUSER contacts_lookup_homepage
2 ROLE_SUPER_USER contacts_lookup_homepage
According to this table only ROLE_NEWUSER
and ROLE_SUPER_USER
are eligible to access the route contacts_lookup_homepage
根据此表,只有
ROLE_NEWUSER
和ROLE_SUPER_USER
才有资格访问路线contacts_lookup_homepage
This way now only those roles are allowed to access contacts_lookup_homepage
route. 现在,仅允许这些角色访问
contacts_lookup_homepage
路由。 Now on the onKernelRequest
all you will do is query this table and check if there is a match with that role with that route. 现在,在
onKernelRequest
上,您要做的就是查询该表并检查该角色与该路由是否匹配。 You have access to both in this method. 您可以使用此方法访问两者。 These routes are the same as the one you define in your
routing.yml
file of every route. 这些路由与您在每条路由的
routing.yml
文件中定义的路由相同。 If you're not sure, it looks something like this: 如果不确定,它看起来像这样:
contacts_lookup_homepage:
path: /Contacts/Lookup
defaults: { _controller: ContactsLookupBundle:Default:index }
Now finally in your onKernelRequest
you can do something like this: 现在终于可以在
onKernelRequest
中执行以下操作:
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
$roleArr = $this->token_storage->getToken()->getUser()->getRoles();
if(!is_int(array_search($route, $routeArr))) //This is for excluding routes that you don't want to check for.
{
//Check for a matching role and route
$qb = $this->em->getRepository('AppBundle:UserAccess')->createQueryBuilder('o');
$qb
->select('o')
->where('o.ROLENAME IN (:roleArr)')
->setParameter('roleArr', $roleArr)
->andWhere('o.ROUTENAME = :route')
->setParameter('route', $route)
;
$result = $qb->getQuery()->getArrayResult();
if(empty($result))
{
//A matching role and route was not found so we do not give access to the user here and redirect to another page.
$event->setResponse(new RedirectResponse($this->router->generate('user_management_unauthorized_user', array())));
}
}
}
The services.yml
can be like this: 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 }
This will guarantee that no unauthorized user accesses the controller action which is not authorized. 这将确保没有未经授权的用户访问未经授权的控制器操作。 I hope that gives you an idea about the implementation.
希望您能对实现有所了解。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.