簡體   English   中英

如何在不覆蓋 checkAccess 和 hasAccess 方法的情況下控制對操作的訪問

[英]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 服務。

要解決我的情況,請按照下列步驟操作:

  1. 創建自定義 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
    {
    }
}
  1. 在 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
  1. 使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM