这篇文章旨在成为这篇文章的第二部分,所以你可能必须阅读它才能理解这个问题。有了上一篇文章中的信息和答案,并且发现了这个有用的UserBundle,它帮助我举例说明roles
和users
之间可能的关系,如Many To Many
,我可能会问:
- 我有动态角色,现在我如何使用这些新的
ROLES
我的意思是,例如,我想将现有函数限制为角色ROLE_NEWROLE
,该角色是动态创建的,因此在基本代码(原始源代码)中不存在,那么我如何将现有函数约束为该新角色?以这里的文档为例:
use Sensio'Bundle'FrameworkExtraBundle'Configuration'Security;
class PostController extends Controller
{
/**
* @Security("has_role('ROLE_ADMIN')")
*/
public function indexAction()
{
// ...
}
}
上面的代码假设ROLE_ADMIN
已经在某个地方声明了,但如果我想通过安全组件将新的ROLE_NEWROLE
添加到该函数中呢?我需要一直触摸我的代码吗?这一点都不好笑,所以我想知道你对这个话题的看法。
正如我们之前所讨论的,您需要实现EventListener
,它将监听您的onKernelRequest
。
简单地说,这意味着所有控制器操作将在访问原始控制器之前首先执行onKernelRequest
。这样你就不用写了
/**
* @Security("has_role('ROLE_ADMIN')")
*/
在每个控制器动作中。
现在,这取决于你想用这种方法做什么。我的方法是制作一个表,将ROLE
与ROUTE
关联起来。此表将相对较大,因为您必须包括所有ROLES
,以便访问所有ROUTES
。
表格结构可以是这样的:
ACCESSID ROLENAME ROUTENAME
1 ROLE_NEWUSER contacts_lookup_homepage
2 ROLE_SUPER_USER contacts_lookup_homepage
根据该表,只有ROLE_NEWUSER
和ROLE_SUPER_USER
有资格访问路由contacts_lookup_homepage
通过这种方式,现在只允许这些角色访问contacts_lookup_homepage
路由。现在,在onKernelRequest
上,您所要做的就是查询该表,并检查该路由是否与该角色匹配。您可以在此方法中访问这两个。这些路由与您在每条路由的routing.yml
文件中定义的路由相同。如果你不确定,它看起来像这样:
contacts_lookup_homepage:
path: /Contacts/Lookup
defaults: { _controller: ContactsLookupBundle:Default:index }
现在终于在你的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())));
}
}
}
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 }
这将保证没有未授权的用户访问未经授权的控制器操作。我希望这能给你一个关于实施的想法。