如何在Symfony2中动态处理角色|权限:限制具有动态角色的函数

时间:2015-12-11 03:54:52

标签: php symfony security authentication authorization

这篇文章的目的是成为this帖子的第二部分,所以你可能需要阅读它才能理解这个问题。获得该信息和之前帖子的答案,并且还发现了this有用的 UserBundle ,这有助于我举例说明Many To Manyroles之间的可能关系users ROLES我可能会问:

  • 我有动态角色,现在我如何使用新ROLE_NEWROLE

我的意思是,例如我想将现有的函数限制为动态创建的角色use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; class PostController extends Controller { /** * @Security("has_role('ROLE_ADMIN')") */ public function indexAction() { // ... } } ,因此在基本代码(原始资源)上不存在,那么我该如何限制这个新角色的存在功能?以文档here为例:

ROLE_ADMIN

上面的代码假定ROLE_NEWROLE已经在某处以某种方式声明了,但是如果我想通过安全组件将新的s[i] = tolower(s[i]); 添加到该函数中该怎么办?我是否需要一直触摸我的代码?这根本不好笑,所以我想知道你对这个话题的看法。

1 个答案:

答案 0 :(得分:1)

在我们谈到这个before时,您需要实施EventListener,这将听取您的onKernelRequest

简单来说,这意味着您的控制器操作的全部将首先执行onKernelRequest,然后才能访问原始控制器。所以这样你就不必写了

/**
* @Security("has_role('ROLE_ADMIN')")
*/

在每个控制器动作中。

现在,你想要在这个方法中做什么。我的方法是创建一个将ROLEROUTE相关联的表格。此表格相对较大,因为您必须包含要授予所有ROLES访问权限的所有ROUTES

表结构可以是这样的:

ACCESSID      ROLENAME                ROUTENAME
    1       ROLE_NEWUSER       contacts_lookup_homepage
    2       ROLE_SUPER_USER    contacts_lookup_homepage

根据此表,只有ROLE_NEWUSERROLE_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 }

这将保证没有未经授权的用户访问未经授权的控制器操作。我希望能让您了解实施情况。