如何在不覆盖checkAccess和hasAccess方法的情况下控制对操作的访问



从SonataAdminBundle的3.102.0版本开始,AbstractAdmin中的许多方法被标记为final。最重要的(在我看来)是"checkaccess"。和";hasAccess"方法也被标记为&;final&;并且不能再在Admin类中重写以自己处理对操作的访问。如何处理的情况下,我想根据对象的状态限制访问一些动作?

例如我有"Task"实体:

<?php
class Task
{
private ?int $id = null;
private ?string $name = null;
private bool $closed = false;
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function isClosed(): bool
{
return $this->closed;
}
public function setClosed(bool $closed): self
{
$this->closed = $closed;
return $this;
}
}

我想要拒绝访问编辑操作,如果任务对象是关闭的。

在3.102版本之前,这样做很简单:

<?php
class TaskAdmin extends AbstractAdmin
{
protected function checkAccess($action, $object = null)
{
if ('edit' === $action && $object && $object->isClosed()) {
throw new AccessDenied('Access Denied to action edit because task is closed.');
}
parent::checkAccess($action, $object);
}
protected function hasAccess($action, $object = null)
{
if ('edit' === $action && $object && $object->isClosed()) {
return false;
}
return parent::hasAccess($action, $object);
}
}

当然现在我不能重写这些方法。

我考虑过投票者,但在这种情况下并不完美,因为Sonata首先检查用户是否具有"超级管理员角色"。如果没有,那么接下来检查特定的角色(例如在我的例子中是ROLE_ADMIN_TASK_TASK_EDIT)。因此,拥有超级管理员角色的用户仍然可以编辑任务对象,即使它被关闭。

另一个想法是为这个TaskAdmin创建Controller并覆盖"preEdit"方法并检查对象是否关闭并拒绝访问。这个解决方案也不是完美的,因为在模板中的许多地方都触发了&;hasaccess &;方法来检查UI的某些部分是否应该可见(例如编辑按钮),因此用户仍然会看到编辑按钮,但将无法进入编辑操作(防止在控制器级别)。

如果有诸如"preCheckAccess"one_answers";preHasAccess"可以在Admin类中重写(如果"checkAccess"one_answers";hasAccess"方法必须保持标记为final)。

还有其他想法吗?谢谢你的帮助。

解决方案是为特定的Admin类创建和使用自定义SecurityHandler服务。

要解决我的问题,请遵循以下步骤:

  1. 创建自定义SecurityHandler类:
// src/Security/Handler/TaskSecurityHandler.php
<?php

namespace AppSecurityHandler;
use AppEntityTask;
use SonataAdminBundleSecurityHandlerSecurityHandlerInterface;
class TaskSecurityHandler extends SecurityHandlerInterface
{
private SecurityHandlerInterface $defaultSecurityHandler;
public function __construct(SecurityHandlerInterface $defaultSecurityHandler)
{
$this->defaultSecurityHandler = $defaultSecurityHandler;
}
public function isGranted(AdminInterface $admin, $attributes, ?object $object = null): bool
{
// Handle custom access logic
if (is_string($attributes) && 'EDIT' === $attributes && $object instanceof Task && $object->isClosed()) {
return false;
}
// Leave default access logic
return $this->defaultSecurityHandler->isGranted($admin, $attributes, $object);
}
public function getBaseRole(AdminInterface $admin): string
{
return '';
}
public function buildSecurityInformation(AdminInterface $admin): array
{
return [];
}
public function createObjectSecurity(AdminInterface $admin, object $object): void
{
}
public function deleteObjectSecurity(AdminInterface $admin, object $object): void
{
}
}
  1. 在服务中注册自定义SecurityHandler类。并注入默认SecurityHandler服务:
# config/services.yaml
services:
AppSecurityHandlerTaskSecurityHandler:
arguments:
- '@sonata.admin.security.handler' #default SecurityHandler service configured in global configuration of SonataAdminBundle
  1. 使用security_handler标记指向您的自定义SecurityHandler服务对于特定的管理类:
# config/services.yaml
services:
# ...
app.admin.task:
class: AppAdminTaskAdmin
arguments: [~, AppEntityTask, ~]
tags:
- { name: sonata.admin, manager_type: orm, label: Task, security_handler: AppSecurityHandlerTaskSecurityHandler }

相关内容

  • 没有找到相关文章

最新更新