7

ユーザーが特定のコンテンツを作成できるように Sonata 管理インターフェースをセットアップしましたが、他のユーザーが作成したコンテンツをユーザーが編集できないようにするにはどうすればよいですか?

議論のために、ユーザーがログインしてブログを作成します。ブログのリスト ビューでは、ユーザーが作成したブログのみが表示されます。

現在、すべてがすべてのユーザーに表示されています。

現在、ログインしている特定のユーザーのコンテンツのみを表示することを考えることができる唯一の方法は、テンプレートをオーバーライドすることですか?

しかし、確かに、これは明白で単純な構成設定ですか?

4

1 に答える 1

14

現在ログインしているユーザーのデータのみを表示する方法は他にもあります。

最初に推奨される方法は、Symfony の ACLを使用することです。詳細については、それがどのように機能するか、および Sonata でどのように行うかを示します

ACL を使用したくない場合は、「WHERE adminId=5」などの条件を SQL クエリ (DQL クエリ) に追加して、既定のクエリを変更できます。これはより多くの作業になりますが、基本的な例とその方法を示します。

新しいセッターsetSecurityContextを追加して、services.xml 内の管理サービスの定義を変更します。一部の製品のリストと編集に管理者を使用します。

    <service id="acme_demo_admin.product" class="Acme\Bundle\DemoAdminBundle\Admin\ProductAdmin">
        <tag name="sonata.admin" manager_type="orm" group="product_group" label_catalogue="admin" label="Products"/>
        <argument />
        <argument>Acme\Bundle\DemoAdminBundle\Entity\Product</argument>
        <argument>AcmeDemoAdminBundle:ProductAdmin</argument>

        <call method="setSecurityContext">
            <argument type="service" id="security.context" />
        </call>
    </service>

SecurityContext は、現在ログインしているユーザーに関する情報を含むサービスです。

Acme/Bundle/DemoAdminBundle/Admin/ProductAdmin.php で、セッター setSecurityContext を追加し、createQuery メソッドを変更します。

<?php

namespace Acme\Bundle\DemoAdminBundle\Admin;

use Symfony\Component\Security\Core\SecurityContextInterface;
// ...

class ProductAdmin extends Admin
{
    /**
     * Security Context
     * @var \Symfony\Component\Security\Core\SecurityContextInterface
     */
    protected $securityContext;

    public function setSecurityContext(SecurityContextInterface $securityContext)
    {
        $this->securityContext = $securityContext;
    }

    protected function configureRoutes(RouteCollection $collection)
    {
        //remove all routes except those, you are using in admin and you can secure by yourself
        $collection
                ->clearExcept(array(
                    'list',
                    'edit',
                ))
        ;
    }

    public function createQuery($context = 'list')
    {
        $queryBuilder = $this->getModelManager()->getEntityManager($this->getClass())->createQueryBuilder();

        //if is logged admin, show all data
        if ($this->securityContext->isGranted('ROLE_ADMIN')) {
            $queryBuilder->select('p')
                    ->from($this->getClass(), 'p')
             ;
        } else {
            //for other users, show only data, which belongs to them
            $adminId = $this->securityContext->getToken()->getUser()->getAdminId();

            $queryBuilder->select('p')
                    ->from($this->getClass(), 'p')
                    ->where('p.adminId=:adminId')
                    ->setParameter('adminId', $adminId, Type::INTEGER)
            ;
        }

        $proxyQuery = new ProxyQuery($queryBuilder);
        return $proxyQuery;
    }

    //... configureListFields, configureDatagridFilters etc.
}

ロール SONATA_ADMIN を持たないユーザーは、すべてのレコードを表示できません。

2 番目のステップ - いくつかの特別なルートを確保します。たとえば編集用です。現在ログインしている管理者が指定された製品を編集できるかどうかを確認する必要があります。

独自のセキュリティ ボーター(推奨ソリューション)を作成するか、カスタム CRUD コントローラーを使用できます。

カスタム CRUD コントローラー: Acme/Bundle/DemoAdminBundle/Controller/ProductController.php オーバーロードeditAction

<?php
    namespace Acme\Bundle\DemoAdminBundle\Controller;

    use Sonata\AdminBundle\Controller\CRUDController as Controller;
    use Symfony\Component\Security\Core\Exception\AccessDeniedException;


    class ProductAdminController extends Controller 
    {
        public function editAction($id = null)
        {
            $request = $this->getRequest();
            $id = $request->get($this->admin->getIdParameter());

            $securityContext = $this->get('security.context');
            if (!$securityContext->isGranted('ROLE_ADMIN')) {

               $adminId = $securityContext->getToken()->getUser()->getId();

               $accessGranted = //here you should check if user with adminId can edit product with $id

                if (!$accessGranted) {
                    throw new AccessDeniedException(sprintf('Admin ID %s has no access to product with id %s', $adminId, $id));
                }
            }

            return parent::editAction($id);
        }

    }

ご覧のとおり、多くのメソッドとルートをオーバーロードして、必要な機能を追加できます。しかし、前に言ったように、これはもっと手間がかかるので、メソッドをオーバーロードする代わりに、まず Symfony の ACL (または単に独自のセキュリティ ボーターを作成すること) がプロジェクトで必要なものかどうかを確認してください。

于 2012-10-16T21:26:26.747 に答える