我有一个Symfony2的控制器如下:
/**
* @Security("is_granted('my_permission')")
*/
class MyController extends Controller
{
/**
* @Security("is_granted('another_permission')")
*/
public function myAction()
{
// ...
}
}
它出现在@Security
上注释myAction()
方法覆盖/忽略父@Security
上注释MyController
类。 有没有什么办法让这些堆栈,以避免做:
/**
* @Security("is_granted('my_permission') and is_granted('another_permission')")
*/
public function myAction()
{
// ...
}
在控制器的每一个动作的方法?
它出现在myAction方法重写@security注解/忽略对类myController的父@security注释。
事实上, Sensio\Bundle\FrameworkExtraBundle\Configuration\Security
标注没有允许嵌套配置(见allowArray()
方法)。 所以方法配置将覆盖类配置@Security
注解。
有没有什么办法让这些堆...
没有一个简单的方法,你需要创建三个类,并一招不重新实现整个父代码:
Security.php
namespace AppBundle\Configuration;
/**
* @Annotation
*/
class Security extends \Sensio\Bundle\FrameworkExtraBundle\Configuration\Security
{
public function getAliasName()
{
return 'app_security';
}
public function allowArray()
{
// allow nested configuration (class/method).
return true;
}
}
SecurityConfiguration.php
这个类允许你通过所有安全配置(类/方法)。化合物的最终安全表达。
namespace AppBundle\Configuration;
class SecurityConfiguration
{
/**
* @var Security[]
*/
private $configurations;
public function __construct(array $configurations)
{
$this->configurations = $configurations;
}
public function getExpression()
{
$expressions = [];
foreach ($this->configurations as $configuration) {
$expressions[] = $configuration->getExpression();
}
return implode(' and ', $expressions);
}
}
SecurityListener.php
namespace AppBundle\EventListener;
use AppBundle\Configuration\SecurityConfiguration;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class SecurityListener extends \Sensio\Bundle\FrameworkExtraBundle\EventListener\SecurityListener
{
public function onKernelController(FilterControllerEvent $event)
{
$request = $event->getRequest();
if (!$configuration = $request->attributes->get('_app_security')) {
return;
}
// trick to simulate one security configuration (all in one class/method).
$request->attributes->set('_security', new SecurityConfiguration($configuration));
parent::onKernelController($event);
}
public static function getSubscribedEvents()
{
// this listener must be called after Sensio\Bundle\FrameworkExtraBundle\EventListener\ControllerListener.
return array(KernelEvents::CONTROLLER => array('onKernelController', -1));
}
}
services.yml
services:
app.security.listener:
class: AppBundle\EventListener\SecurityListener
parent: sensio_framework_extra.security.listener
tags:
- { name: kernel.event_subscriber }
最后,只需用@AppBundle\Configuration\Security
注解来替代标准之一。
这里是我的尝试:
使用,在app/config/security.yml
,这个角色层次:
role_hierarchy:
ROLE_CLASS: ROLE_CLASS
ROLE_METHOD: [ROLE_CLASS, ROLE_METHOD]
如果我有两个用户: user1
与ROLE_CLASS
和user2
与ROLE_METHOD
(这意味着该用户有两个角色),然后第一用户可以看到控制器内创建的所有页面,除了有额外限制的人。
控制器例如:
/**
* @Security("is_granted('ROLE_CLASS')")
*/
class SomeController extends Controller
{
/**
* @Route("/page1", name="page1")
* @Security("is_granted('ROLE_METHOD')")
*/
public function page1()
{
return $this->render('default/page1.html.twig');
}
/**
* @Route("/page2", name="page2")
*/
public function page2()
{
return $this->render('default/page2.html.twig');
}
}
所以,因为user1
具有ROLE_CLASS
,他能看到的只是/page2
,而不是/page1
,他将获得403 Expression "is_granted('ROLE_METHOD')" denied access.
错误(dev的明显)。 在另一方面, user2
,有ROLE_METHOD
(和ROLE_CLASS
),他是能够看到这两个网页。