繁体   English   中英

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

[英]How I can add a “roles” to a “path” dynamically in Symfony2?

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

应用\\配置\\安全.yml

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

我需要手动添加可以访问此“路径”的每个“路径”和“角色”。 我怎样才能动态地做到这一点? 像 Yii2 上的 RBAC:

在此处输入图片说明

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

应用\\配置\\安全.yml

security:
    access_control:
         type: dynamically

如果您想让添加角色更容易,您可以使用注释

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

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

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();
    }

    // ...
}

如果您希望在许多控制器中使用上述代码,则会导致重复代码,因此您还可以创建一个投票者

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所采用的方法。

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

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

<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")
        }


}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM