[英]How to control access to actions without override checkAccess and hasAccess methods
從 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);
}
}
當然,現在我無法覆蓋這些方法。
我考慮過選民,但在這種情況下並不完美,因為奏鳴曲首先檢查用戶是否具有“超級管理員角色/角色”。 如果沒有,則接下來檢查特定角色(例如在我的情況下 ROLE_ADMIN_TASK_TASK_EDIT)。 因此,即使 Task 對象已關閉,具有超級管理員角色的用戶仍然可以編輯它。
另一個想法是為此 TaskAdmin 創建控制器並覆蓋“preEdit”方法並檢查對象是否已關閉並拒絕訪問。 這個解決方案也不是完美的,因為在模板的很多地方會觸發“hasAccess”方法來檢查UI的某些部分是否應該可見(例如編輯按鈕),所以用戶仍然會看到編輯按鈕但不會能夠進入編輯操作(在控制器級別阻止)。
如果有可以在 Admin 類中覆蓋的方法,例如“preCheckAccess”和“preHasAccess”(如果“checkAccess”和“hasAccess”方法必須保持標記為 final),那將是完美的。
還有其他想法嗎? 謝謝你的幫助。
您可以使用選民
在其中檢查任務是否已關閉
switch ($attribute) {
case self::EDIT:
return !$subject->isClosed();
}
如果您有多個投票者(您的和/或 Sonata 投票者),請查看訪問決策策略
例如,您可以將策略設置為unanimous
,這將使用戶只有在奏鳴曲和您的選民授予訪問權限時才能訪問
另一個例子,你可以在你的選民中定義整個邏輯(也檢查用戶角色)並將策略設置為priority
,然后你可以給你的選民一個高優先級,這樣你的選民將始終被執行而不是奏鳴曲
最后閱讀所有選項並為您做最合適的解決方案,因為我們不知道您所有的代碼上下文
解決方案是為特定的 Admin 類創建和使用自定義 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
{
}
}
# config/services.yaml
services:
App\Security\Handler\TaskSecurityHandler:
arguments:
- '@sonata.admin.security.handler' #default SecurityHandler service configured in global configuration of SonataAdminBundle
security_handler
標記指向特定 Admin 類的自定義 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 }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.