如何在Symfony2中动态地将“角色”添加到“路径”?

时间:2015-04-14 04:25:22

标签: php symfony yii2 acl rbac

我是Symfony2的初学者,虽然已经开发了PHP多年(ZF1,ZF2,CakePHP)。

在SF2中,根据站点本身的文档,我有以下场景:

应用\设置\ security.yml

security:
    access_control:
         - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
         - { path: ^/, roles: ROLE_ADMIN }

我需要手动添加每个"路径"和#34;角色"可以访问这个"路径"。 我怎么能动态地这样做? 就像Yii2上的RBAC一样:

enter image description here

是否有任何现成的Bundle或SF2自己的文档允许这样做?作为假设的例子:

应用\设置\ security.yml

security:
    access_control:
         type: dynamically

PS:对不起主持人,我不知道怎么问这个。请帮我改进我的问题。

2 个答案:

答案 0 :(得分:1)

如果您想更轻松地添加角色,可以使用annotations

您的问题要求动态安全,这很复杂。在缓存预热阶段编译路由和所有角色。因此,为此,您首先需要存储动态值。数据库将是一个很好的选择。在这里,我只展示如何检查角色,我将留给你的实际角色操作。

最简单的方法是将授权检查程序注入您的控制器。

services:
    acme_controller:
        class:     "AcmeDemoBundle\Controller"
        arguments: ["@security.authorization_checker"]

然后检查操作中的角色:

public function __construct(AuthorizationCheckerInterface $authorizationChecker)
{
    $this->authorizationChecker = $authorizationChecker;
}

public function listAction()
{
    $role = /* load your role here */;
    if (false === $this->authorizationChecker->isGranted($role)) {
        throw new AccessDeniedException();
    }

    // ...
}

如果你想在多个控制器中使用上面的代码,那么你也可以创建一个voter

services:
    acme.route.voter:
        class: AcmeDemoBundle\RouteVoter
        arguments:
            - @security.role_hierarchy
        public: false
        tags:
            - { name: security.voter, priority: 300 }

示例:

public function __construct ( RoleHierarchyInterface $roleHierarchy )
{
    $this->roleVoter   = new RoleHierarchyVoter( $roleHierarchy );
}

public function vote ( TokenInterface $token, $object, array $attributes )
{
    if ( !$object instanceof Request ) {
        return VoterInterface::ACCESS_ABSTAIN;
    }

    $requestUri = $object->getPathInfo();

    if ( isset($this->votes[ $requestUri ]) ) {
        return $this->votes[ $requestUri ];
    }

    $roles = /* load your roles */;

    return $this->votes[ $requestUri ] = $this->roleVoter->vote( $token, $object, $roles );
}

另一种方法是用您自己的实现替换router服务。这是采用CMF Bundle

的方法

答案 1 :(得分:1)

您可以像这样动态管理角色/路线关系:

您在内核上创建一个侦听器

<service id="toto.security.controller_listener" class="Administration\SecurityBundle\EventListener\SecurityListener">
    <tag name="kernel.event_listener" event="kernel.controller" method="onKernelController" />
    <argument type="service" id="service_container" />
</service>

然后在监听器中实现此方法

public function onKernelController(FilterControllerEvent $event)
    {
      $controller = $event->getController();
      if (!is_array($controller)) {
        return;
      }



        $request = $event->getRequest();

        $baseUrl = $request->getBaseUrl();
        $requestUri = $request->getRequestUri();
        $route = str_replace($baseUrl, "", $requestUri);
        //you put your check logic
        //you can implement a relation beetween routes  and roles/ users in database etc. you got the entire control on what you do
        if(!$this->accessMananager->isGrantAccess(User $user, $route)){
           throw new AccessDeniedException("blah blah blah")
        }


}

由于此侦听器将始终在任何控制器之前调用,因此请考虑创建缓存系统