且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何动态手柄角色|在Symfony2的权限:限制使用动态角色功能

更新时间:2023-11-19 15:42:04

正如我们之前谈到这个,你需要实施的EventListener 将倾听你的 onKernelRequest

As we talked about this before, you need to implement EventListener which will listen to your onKernelRequest.

在简单的英语,这意味着您的控制器操作的所有将执行 onKernelRequest 先给予访问原始控制器之前。所以,这样你就不必写

In plain English, this means that all of your Controller Actions will execute onKernelRequest first before giving access to the original controller. So this way you won't have to write

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

在每个控制器动作。

现在,其高达你想要的在这个方法中做什么。我的方法是使该相关联的角色路线表。该表将是比较大的,因为你必须包括所有的角色你想给访问所有路线

Now, its upto you what you want to do in this method. My approach was to make a table which associates a ROLE with a ROUTE. This table will be comparatively big because you have to include all ROLES you want to give access to all ROUTES.

表结构可以是这样的:

ACCESSID      ROLENAME                ROUTENAME
    1       ROLE_NEWUSER       contacts_lookup_homepage
    2       ROLE_SUPER_USER    contacts_lookup_homepage

根据此表仅 ROLE_NEWUSER ROLE_SUPER_USER 有资格进入的路线 contacts_lookup_homepage

这种方式现在只有这些角色被允许访问 contacts_lookup_homepage 路线。现在,在 onKernelRequest 所有你要做的就是查询这个表,检查是否存在与与路由的角色匹配。你必须在该方法中访问两者。这些路由是一样的,你在每一个路线的的routing.yml 文件中定义之一。如果你不知道,它看起来是这样的:

This way now only those roles are allowed to access contacts_lookup_homepage route. Now on the onKernelRequest all you will do is query this table and check if there is a match with that role with that route. You have access to both in this method. These routes are the same as the one you define in your routing.yml file of every route. If you're not sure, it looks something like this:

contacts_lookup_homepage:
    path:     /Contacts/Lookup
    defaults: { _controller: ContactsLookupBundle:Default:index }

现在终于在你的 onKernelRequest 你可以做这样的事情:

Now finally in your onKernelRequest you can do something like this:

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 }

这将保证未经授权的用户访问未授权的控制器操作。我希望为您提供有关实施的想法。

This will guarantee that no unauthorized user accesses the controller action which is not authorized. I hope that gives you an idea about the implementation.