在我的 Symfony 2 应用程序中,我有 3 个不同的用户角色可以访问后端管理部分:
role_hierarchy:
ROLE_STAFF: ROLE_USER
ROLE_MODERATOR: ROLE_STAFF
ROLE_ADMIN: ROLE_MODERATOR
对于像这样的路由http://example.org/admin/post/
,我希望我的应用根据用户角色显示不同的信息,这意味着3 个控制器绑定到唯一的路由。
处理此问题的最佳方法是什么?
我正在考虑一些解决方案,但似乎没有一个对我有好处:
一个控制器,在每个操作中我只测试用户角色:
<?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); } }
即使这样做了,IMO 显然这不是一个好的设计。
一个 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; } }
和一号一样。
我试图让控制器相互扩展:
<?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); } }
IMO 这是一个更好的设计,但我无法让它工作。路由系统在它匹配的第一个控制器上停止。我想让它自动成为级联风格的王者(即,如果用户是员工,则转到 PostStaffController,否则如果用户是版主,则转到 PostModeratorController,否则转到 PostAdminController)。
在我的 BlogBundle 中为 kernel.controller 添加一个监听器,它的工作与数字 2 相同吗?
我正在寻找最好的设计和更灵活的解决方案,我们有机会在未来增加更多的角色。