【问题标题】:Symfony: How to trigger custom security voter for dynamic routesSymfony:如何为动态路由触发自定义安全投票器
【发布时间】:2016-06-30 23:01:13
【问题描述】:

我有以下设置:

  • 动态路由加载器,它根据数据库中有关应用程序视图的信息生成路由并调用适当的控制器

  • 自定义安全投票器,用于验证用户是否应有权访问当前视图

我当然可以从适当的控制器中调用 is_granted 方法并且它可以工作。我想做的不是从控制器内部触发投票者(这需要在每个控制器中重复自己,只是使用不同的视图 ID),而是为路由加载器中生成的每条路由自动触发它。这样我就不必执行对每条路线基本相同的标准验证 - 检查用户是否有权访问此视图,但专注于业务逻辑,这可能需要满足用户访问此路线的额外要求(以及是控制器中的内容)。

我的方向是路由生成方法中有一些参数:

    $route = new Route($path, $defaults, $requirements);

    $routes->add($routeName, $route);

这将允许我为创建的路由触发 is_granted,但有关参数的文档很少。

有谁知道如何将这种要求传递给用户,例如。对于创建的路由需要用户 is_granted('VIEW_1')?

【问题讨论】:

    标签: php symfony


    【解决方案1】:

    您可以将任何您想要的内容添加到默认数组中,它们将被传递。例如:

    cerad_game__project__game__update__by_scorer:
      path:  /project/{_project}/game/{_game}/update-by-scorer
      defaults:
        _role:       ROLE_SCORER_ADMIN
        _model:      cerad_game__project__game__update__by_scorer__model_factory
        _form:       cerad_game__project__game__update__by_scorer__form_factory
        _controller: cerad_game__project__game__update__by_scorer__controller:action
        _template: '@CeradGame/Project/Game/Update/ByScorer/GameUpdateByScorerTwigPage.html.twig'
    

    然后,您将创建一个内核控制器侦听器,该侦听器将在控制器解析之后但在调用控制器操作方法之前调用。

    class ModelEventListener extends ContainerAware implements EventSubscriberInterface {
    
    public static function getSubscribedEvents()
    {
        return array(
            KernelEvents::CONTROLLER => array(  
                array('onControllerRole',  self::ControllerRoleEventListenerPriority),
                array('onControllerModel', self::ControllerModelEventListenerPriority),
                array('onControllerForm',  self::ControllerFormEventListenerPriority),
            ),
            KernelEvents::VIEW => array(
                array('onView', self::ViewEventListenerPriority),
            ),
        );
    }
    
    public function onControllerRole(FilterControllerEvent $event)
    {
        if (!$event->getRequest()->attributes->has('_role')) return;
    
        $role = $event->getRequest()->attributes->get('_role');
    
        $securityContext = $this->container->get('security.context');
    
        if (!$securityContext->isGranted($role))
        {
            // For public it redirects
            // For users we see the exception
            // die('access denied ' . $event->getRequest()->attributes->get('_route'));
            throw new AccessDeniedException(); 
        }
    }
    

    然后接线:

    cerad_core__model_event_listener:
        class:  '%cerad_core__model_event_listener__class%'
        calls:
            - [setContainer, ['@service_container']]
        tags:
            - { name: kernel.event_subscriber }
    

    在此处记录:http://symfony.com/doc/current/cookbook/event_dispatcher/event_listener.html

    请注意,我在这里注入了容器,而不仅仅是安全上下文。我需要其他方法的容器。它也是2.7代码。还没来得及更新到 3.0。

    【讨论】:

    • 非常感谢。绝对正确的解决方案和优雅的通用方法。我对使用 Route 参数的想法非常执着,以至于我需要轻推才能看到正确的方法;)
    猜你喜欢
    • 2016-02-07
    • 2018-02-11
    • 2016-05-17
    • 2015-02-28
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多