簡體   English   中英

Symfony 4選民注解(@IsGranted)

[英]Symfony 4 Voter Annotations (@IsGranted)

我正在嘗試使用Symfony選民和控制器注釋來允許或限制對Symfony 4應用程序中某些操作的訪問。

例如,“我的前端”提供了刪除“帖子”的功能,但前提是用戶為該帖子設置了“ DELETE_POST”屬性。

前端向我的symfony端點發送HTTP“ DELETE”操作,在URL中傳遞帖子的ID(即/api/post/delete/19 )。

我試圖用@IsGranted注釋,如所描述這里

這是我的symfony端點:

/**
 * @Route("/delete/{id}")
 * @Method("DELETE")
 * @IsGranted("DELETE_POST", subject="post")
 */
public function deletePost($post)  {
    ... some logic to delete post
    return new Response("Deleting " . $post->getId());
}

這是我的選民:

class PostVoter extends Voter {

    private $attributes = array(
        "VIEW_POST", "EDIT_POST", "DELETE_POST", "CREATE_POST"
    );

    protected function supports($attribute, $subject) { 
        return in_array($attribute, $this->attributes, true)  &&  $subject instanceof Post;
    }

    protected function voteOnAttribute($attribute, $subject, TokenInterface $token) {
        ... logic to figure out if user has permissions.

        return $check;

    }
}

我遇到的問題是前端只是將資源ID發送到端點。 然后,Symfony通過調用選民並傳入屬性"DELETE_POST"和帖子ID來解析@IsGranted批注。

問題是,$ post只是一個帖子ID,而不是實際的Post對象。 因此,當選民進入$subject instanceof Post它返回false

我嘗試通過將方法簽名更改為public function deletePost(Post $post)Post注入到我的控制器方法中。 當然這是行不通的,因為javascript是在URL中發送ID,而不是Post對象。

(順便說一句:我知道這種注射應該適用於Doctrine,但是我使用Doctrine)。

我的問題是我如何獲得@IsGranted來了解“ post”應該是post對象? 有沒有辦法告訴它從傳入的ID並根據該ID進行評估來查找Post? 甚至遵照另一種控制器方法來確定subject="post"應該代表什么?

謝謝。

UPDATE

感謝@NicolasB,我添加了一個ParamConverter:

class PostConverter implements ParamConverterInterface {
    private $dao;

    public function __construct(MySqlPostDAO $dao) {
        $this->dao = $dao;
    }

    public function apply(Request $request, ParamConverter $configuration)  {
        $name = $configuration->getName();            
        $object = $this->dao->getById($request->get("id"));

        if (!$object)  {
            throw new NotFoundHttpException("Post not found!");
        }

        $request->attributes->set($name, $object);

        return true;
    }

    public function supports(ParamConverter $configuration) {
        if ($configuration->getClass() === "App\\Model\\Objects\\Post")  {
            return true;
        }

        return false;
    }
}

這似乎按預期方式工作。 我什至不必使用@ParamConverter批注使其起作用。 我必須對控制器進行的唯一其他更改是將我的路由的方法簽名更改為public function deletePost(Post $post) (就像我之前嘗試過的-但由於PostConverter而現在可以PostConverter )。

我的最后兩個問題是:

  1. 我應該在supports()方法中檢查什么? 我目前正在檢查類是否匹配。 我還應該檢查$configuration->getName() == "id" ,以確保使用正確的字段嗎?

  2. 我應該如何使其更通用? 我是否假設您ParamConverterInterface將實體注入控制器方法中時,Symfony都會在實現ParamConverterInterface所有對象上調用supports方法?

謝謝。

如果您使用Doctrine會發生什么,那就是您需要鍵入提示$post變量。 完成之后,Doctrine的ParamConverter將負責其余的工作。 現在,Symfony不知道如何將id url占位符與$post參數相關聯,因為它不知道$post指的是哪個實體。 通過使用public function deletePost(Post $post)類的類型進行提示,並使用ParamConverter,Symfony將知道$post引用具有來自URL的id占位符的idPost實體。

從文檔中:

通常,您希望$ id參數可以顯示()。 相反,通過創建一個新參數($ post)並用Post類(這是一個Doctrine實體)進行類型提示,ParamConverter會自動查詢其$ id屬性與{id}值匹配的對象。 如果找不到帖子,它將也顯示404頁面。

然后,選民還將知道什么是$post以及如何對待它。


現在,由於您不使用Doctrine,因此默認情況下沒有ParamConverter,正如我們剛剛看到的,這是這里的關鍵要素。 因此,您要做的只是定義自己的ParamConverter。

Symfony文檔的此頁面將告訴您更多有關如何執行此操作的信息,尤其是最后一節“創建轉換器”。 您將必須告訴它如何使用模型的邏輯將字符串"id"轉換為Post對象。 首先,您可以使其非常特定於Post對象(並且您可能希望使用converter="name"選項在批注中顯式引用該ParamConverter)。 稍后,當您有了可用的版本時,就可以使其更通用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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