8

私の Symfony 2 アプリには、バックエンド管理部分にアクセスできる 3 つの異なるユーザー ロールがあります。

role_hierarchy:
    ROLE_STAFF:     ROLE_USER
    ROLE_MODERATOR: ROLE_STAFF
    ROLE_ADMIN:     ROLE_MODERATOR

のようなルートhttp://example.org/admin/post/の場合、ユーザーの役割に応じてアプリにさまざまな情報を表示させたいと考えています。つまり、3 つのコントローラーが唯一のルートにバインドされていることを意味します。

これを処理する最良の方法は何ですか?

私はいくつかの解決策を考えていましたが、どれも私にとって良いものではないようです:

  1. 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);
        }
    }
    

    それが機能したとしても、IMO は明らかにそれは良い設計ではありません。

  2. 3 つの異なるコントローラーにディスパッチする 1 つの BackendController :

    <?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;
        }
    }
    

    1号と同じ。

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

    IMO はより良い設計ですが、うまく機能させることができません。ルーティング システムは、一致する最初のコントローラーで停止します。私はそれを自動的にカスケード スタイルのキングとして機能させたいと思います (つまり、ユーザーがスタッフの場合は PostStaffController に移動し、ユーザーがモデレーターの場合は PostModeratorController に移動し、それ以外の場合は PostAdminController に移動します)。

  4. 2番と同じ仕事をするBlogBu​​ndleのkernel.controllerにリスナーを追加しますか?

最適な設計のソリューションを探していますが、より柔軟なソリューションには、将来さらに役割を追加する可能性があります。

4

4 に答える 4

0

2 番目のソリューションの自動化バージョンはどうですか? お気に入り:

    // 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 ...

私はあなたのセットアップを持っていないので、上記のコードをテストしていません。ところで: 何かを投稿する別の方法の違いは何ですか?

于 2012-04-17T16:19:46.347 に答える
0

http://symfony.com/doc/current/book/internals.html#kernel-controller-eventを参照してください

トリックを実行し、必ず security.context サービスを挿入する必要があります

于 2012-04-18T03:04:28.737 に答える
0

vendor/symfony/symfony/src/Symfony/Component/Routing/Router.php

matcher_classで可能なはずのものを置き換えるオプションがありますconfig.yml

UrlMatcherパスの一致よりも優先されるサブクラス化とオーバーライドを行う場合matchRequest(URL のみ)。

matchRequestパラメータ $request (リクエストオブジェクト) を取ります

セキュリティ プロバイダー リスナーがルーター リスナーの前に実行され、URL とユーザー ロールを組み合わせてルートを選択できる場合、Request オブジェクトにはユーザー情報が含まれている必要があります。ルートは名前でインデックス付けされた配列に格納されるため、名前は異なる必要があります。

次のような名前を使用できますpost_index[USER] post_index[STAFF] post_index[MODERATOR]

URL を生成するには、サブクラスを置き換えて、それをオプションで Router に挿入{{ path('post_index', {...}) }}する必要もあります。URLGeneratorgenerator_class

于 2015-09-02T12:10:22.653 に答える