從 SonataAdminBundle 的 3.102.0 版本開始,AbstractAdmin 中的很多方法都被標記為 final。最重要的(在我看來)“checkAccess”和“hasAccess”方法也被標記為“final”并且不能再在 Admin 類中被覆寫來處理對我自己的操作的訪問。當我想根據物件的狀態限制對某些操作的訪問時,如何處理?
例如我有“任務”物體:
<?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;
}
}
如果 Task 物件關閉,我想拒絕訪問編輯操作。
在 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);
}
}
當然,現在我無法覆寫這些方法。
I thought about Voters but in this case is not perfect, because Sonata checks first if user have "Super admin role/roles". If not, then next is checked specific role (for example ROLE_ADMIN_TASK_TASK_EDIT in my case). So, user with super admin role will still be able to edit Task object even though it is closed.
Another idea was create Controller for this TaskAdmin and override "preEdit" method and check there if object is closed or not and denied access. This solution is also not perfect, because in many places in templates is fired "hasAccess" method to checks if some parts of UI should be visible or not (for example edit button), so the user will still see the edit button but will not be able to enter the edit action (prevents on controller level).
如果有可以在 Admin 類中覆寫的方法,例如“preCheckAccess”和“preHasAccess”(如果“checkAccess”和“hasAccess”方法必須保持標記為 final),那將是完美的。
還有其他想法嗎?謝謝你的幫助。
uj5u.com熱心網友回復:
解決方案是為特定的 Admin 類創建和使用自定義 SecurityHandler 服務。
要解決我的情況,請按照下列步驟操作:
- 創建自定義 SecurityHandler 類:
// src/Security/Handler/TaskSecurityHandler.php
<?php
namespace App\Security\Handler;
use App\Entity\Task;
use Sonata\AdminBundle\Security\Handler\SecurityHandlerInterface;
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
{
}
}
- 在 services.yaml 中注冊自定義 SecurityHandler 類并注入默認的 SecurityHandler 服務:
# config/services.yaml
services:
App\Security\Handler\TaskSecurityHandler:
arguments:
- '@sonata.admin.security.handler' #default SecurityHandler service configured in global configuration of SonataAdminBundle
- 使用
security_handler標記指向特定管理類的自定義 SecurityHandler 服務:
# config/services.yaml
services:
# ...
app.admin.task:
class: App\Admin\TaskAdmin
arguments: [~, App\Entity\Task, ~]
tags:
- { name: sonata.admin, manager_type: orm, label: Task, security_handler: App\Security\Handler\TaskSecurityHandler }
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/350074.html
標籤:php symfony symfony4 奏鸣曲管理员 奏鸣曲
上一篇:每次遷移都會改變uuid列的學說
