Аннотации избирателей Symfony 4 (@IsGranted) - PullRequest
0 голосов
/ 02 октября 2018

Я пытаюсь использовать аннотации для избирателей и контроллеров Symfony, чтобы разрешить или ограничить доступ к определенным действиям в моем приложении Symfony 4.

Например, мой интерфейс предоставляет возможность удалить сообщение", но только если у пользователя установлен атрибут" DELETE_POST " для этого сообщения .

Внешний интерфейс отправляет HTTP-действие" DELETE "в мою конечную точку Symfony, передавая идентификаторсообщение в URL (т.е. /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;

    }
}

Проблема, с которой я столкнулся, заключается в том, что мой интерфейс просто отправляет идентификатор ресурса моей конечной точке.Затем Symfony разрешает аннотацию @IsGranted, вызывая избирателей и передавая атрибут "DELETE_POST" и идентификатор сообщения.

Проблема в том, что $ post - это просто идентификатор сообщения, а не фактический объект Post.Поэтому, когда избиратель достигает $subject instanceof Post, он возвращает false.

Я попытался ввести Post в метод моего контроллера, изменив сигнатуру метода на public function deletePost(Post $post).Конечно, это не работает, потому что javascript отправляет идентификатор в URL, а не объект Post.

(Кстати: я знаю, что этот тип инъекций должен работать с Doctrine, но я не с использованием Doctrine).

Мой вопрос: как мне получить @IsGranted, чтобы понять, что "post" должен быть объектом post?Есть ли способ сказать ему, чтобы искать Post от идентификатора, переданного и оцененного на основании этого?Или даже обратиться к другому методу контроллера, чтобы определить, что subject="post" должно представлять?

Спасибо.

ОБНОВЛЕНИЕ

Благодаря @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).

Мои последние двавопросы будут:

  1. Что именно я должен проверить в методе supports()?В настоящее время я просто проверяю соответствие класса.Должен ли я также проверить это $configuration->getName() == "id", чтобы убедиться, что я работаю с правильным полем?

  2. Как мне сделать его более универсальным?Правильно ли я полагаю, что каждый раз, когда вы вводите сущность в метод контроллера, Symfony будет вызывать метод supports для всего, что реализует ParamConverterInterface?

Спасибо.

1 Ответ

0 голосов
/ 02 октября 2018

Что бы произошло, если бы вы использовали Doctrine, вам нужно было бы напечатать подсказку для вашей переменной $post.После того, как вы это сделаете, ParamConverter из Doctrine позаботится обо всем остальном.В настоящее время Symfony не имеет представления о том, как связать заполнитель вашего id url с вашим параметром $post, поскольку он не знает, к какому объекту относится $post.Подсказав типу что-то вроде public function deletePost(Post $post) и используя ParamConverter, Symfony будет знать, что $post относится к сущности Post с идентификатором из заполнителя id URL.

Из документа:

Обычно вы ожидаете, что аргумент $ id будет отображаться ().Вместо этого, создав новый аргумент ($ post) и указав на него тип с помощью класса Post (который является сущностью Doctrine), ParamConverter автоматически запрашивает объект, свойство $ id которого соответствует значению {id}.Он также покажет страницу 404, если сообщение не будет найдено.

Избиратель также узнает, что такое $post и как с ним обращаться.


Сейчаспоскольку вы не используете Doctrine, у вас нет ParamConverter по умолчанию, и, как мы только что видели, это ключевой элемент.Поэтому вам нужно просто определить свой собственный ParamConverter.

Эта страница документации Symfony расскажет вам больше о том, как это сделать, особенно в последнем разделе.«Создание конвертера».Вы должны будете рассказать ему, как преобразовать строку "id" в Post объект, используя логику вашей модели.Сначала вы можете сделать это очень специфичным для Post объектов (и вы можете явно ссылаться на этот один ParamConverter в аннотации, используя опцию converter="name").Позже, когда вы получите рабочую версию, вы можете сделать ее более общей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...