我已经设置了一个允许用户创建特定内容的奏鸣曲管理界面,但是如何限制用户编辑其他用户创建的内容?
为了争论,用户登录并创建博客。在博客列表视图中,应该只显示用户创建的博客。
目前,所有内容都显示给每个用户——我确实设置了组/角色来限制对管理区域的访问,这很好。
我目前能想到的仅显示特定登录用户内容的唯一方法是覆盖模板?
但是,当然,这是一个明显而简单的配置设置?
我已经设置了一个允许用户创建特定内容的奏鸣曲管理界面,但是如何限制用户编辑其他用户创建的内容?
为了争论,用户登录并创建博客。在博客列表视图中,应该只显示用户创建的博客。
目前,所有内容都显示给每个用户——我确实设置了组/角色来限制对管理区域的访问,这很好。
我目前能想到的仅显示特定登录用户内容的唯一方法是覆盖模板?
但是,当然,这是一个明显而简单的配置设置?
还有更多选项如何仅显示当前登录用户的数据:
第一种首选方法是使用Symfony 的 ACL,这里有更多信息,它是如何工作的以及如何在 Sonata 中做到这一点。
如果您不想使用 ACL,可以通过在 SQL 查询(DQL 查询)中添加一些条件来更改默认查询,例如“ WHERE adminId=5 ”。这将是更多的工作,但我将向您展示基本示例,如何做到这一点。
通过添加新的 setter 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 添加 setter 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 的用户无法查看所有记录。
第二步 - 保护一些特殊路线,例如编辑- 您应该检查当前登录的管理员是否可以编辑指定的产品。
您可以创建自己的安全投票者(首选解决方案)或使用自定义 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(或者只是创建自己的安全投票器)是否是您项目中需要的。