根据用户角色将一条路由绑定到不同的控制器

iam*_*dto 8 symfony

在我的Symfony 2应用程序中,我有3个不同的用户角色,可以访问后端管理部分:

role_hierarchy:
    ROLE_STAFF:     ROLE_USER
    ROLE_MODERATOR: ROLE_STAFF
    ROLE_ADMIN:     ROLE_MODERATOR
Run Code Online (Sandbox Code Playgroud)

对于像这样的路线http://example.org/admin/post/,我希望我的应用程序根据用户角色显示不同的信息,这意味着3个控制器绑定到唯一的路径.

处理这个问题的最佳方法是什么?

我在考虑一些解决方案,但似乎没有一个对我好:

  1. 一个控制器,在每个动作中我只测试用户角色:

    <?php
    
    /**
     * @Route("/admin/post")
     */
    class PostController extends Controller
    {
        /**
         * Lists all post entities.
         *
         * @Route("/", name="post_index")
         * @Template()
         * @Secure(roles="ROLE_STAFF")
         */
        public function indexAction()
        {
            $user = $this->get('security.context')->getToken()->getUser();
    
            if ($this->get('security.context')->isGranted('ROLE_STAFF')) {
                // Do ROLE_STAFF related stuff
            } else if ($this->get('security.context')->isGranted('ROLE_MODERATOR')) {
                // Do ROLE_MODERATOR related stuff
            } else if ($this->get('security.context')->isGranted('ROLE_ADMIN')) {
                // Do ROLE_ADMIN related stuff
            }
    
            return array('posts' => $posts);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    即使这样做,IMO显然不是一个好的设计.

  2. 一个BackendController调度到3个不同的控制器:

    <?php
    
    /**
     * @Route("/admin/post")
     */
    class PostBackendController extends Controller
    {
        /**
         * Lists all post entities.
         *
         * @Route("", name="admin_post_index")
         * @Template("AcmeBlogBundle:PostAdmin:index.html.twig")
         * @Secure(roles="ROLE_STAFF")
         */
        public function indexAction()
        {
            if ($this->get('security.context')->isGranted('ROLE_STAFF')) {
                $response = $this->forward('AcmeBlogBundle:PostStaff:index');
            } else if ($this->get('security.context')->isGranted('ROLE_MODERATOR')) {
                $response = $this->forward('AcmeBlogBundle:PostModerator:index');
            } else if ($this->get('security.context')->isGranted('ROLE_ADMIN')) {
                $response = $this->forward('AcmeBlogBundle:PostAdmin:index');
            }
    
            return $response;
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    与第一名相同.

  3. 我试图使控制器彼此扩展:

    <?php
    
    /**
     * @Route("/admin/post")
     */
    class PostStaffController extends Controller
    {
        /**
         * Lists all post entities.
         *
         * @Route("/", name="post_index")
         * @Template()
         * @Secure(roles="ROLE_STAFF")
         */
        public function indexAction()
        {
            $user = $this->get('security.context')->getToken()->getUser();
    
            // Do ROLE_STAFF related stuff
    
            return array('posts' => $posts);
        }
    }
    
    <?php
    
    /**
     * @Route("/admin/post")
     */
    class PostModeratorController extends PostStaffController
    {
        /**
         * Lists all post entities.
         *
         * @Route("/", name="post_index")
         * @Template()
         * @Secure(roles="ROLE_MODERATOR")
         */
        public function indexAction()
        {
            $user = $this->get('security.context')->getToken()->getUser();
    
            // As PostModeratorController extends PostStaffController,
            // I can either use parent action or redefine it here
    
            return array('posts' => $posts);
        }
    }
    
    <?php
    
    /**
     * @Route("/admin/post")
     */
    class PostAdminController extends PostModeratorController
    {
        /**
         * Lists all post entities.
         *
         * @Route("/", name="post_index")
         * @Template()
         * @Secure(roles="ROLE_ADMIN")
         */
        public function indexAction()
        {
            $user = $this->get('security.context')->getToken()->getUser();
    
            // Same applies here
    
            return array('posts' => $posts);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    IMO它是一个更好的设计,但我无法使其成功.路由系统在匹配的第一个控制器上停止.我想让它自动成为级联风格的王者(即如果用户是工作人员则转到PostStaffController,否则如果用户是主持人转到PostModeratorController,否则转到PostAdminController).

  4. 在我的BlogBu​​ndle中为kernel.controller添加一个监听器,它将完成与2号相同的工作?

我正在寻找最好的设计和更灵活的解决方案,我们有可能在未来增加更多的角色.

pre*_*ldt 0

您的第二个解决方案的自动化版本怎么样?喜欢:

    // Roles ordered from most to least significant (ROLE_ADMIN -> ROLE_MODERATOR -> etc)
    $roles = $myUserProvider->getRoles();
    foreach ($roles as $role) {
        // add a check to test, if the function you're calling really exists
        $roleName = ucfirst(strtolower(mb_substr($role, 0, 5)));
        $response = $this->forward(sprintf('AcmeBlogBundle:Post%s:index', $roleName))

        break;
    }

    // Check that $response is not null and do something with it ...
Run Code Online (Sandbox Code Playgroud)

由于我没有你的设置,所以我没有测试上面的代码。顺便说一句:不同的发布方法有什么区别?