Я пытаюсь использовать аннотации для избирателей и контроллеров 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
).
Мои последние двавопросы будут:
Что именно я должен проверить в методе supports()
?В настоящее время я просто проверяю соответствие класса.Должен ли я также проверить это $configuration->getName() == "id"
, чтобы убедиться, что я работаю с правильным полем?
Как мне сделать его более универсальным?Правильно ли я полагаю, что каждый раз, когда вы вводите сущность в метод контроллера, Symfony будет вызывать метод supports
для всего, что реализует ParamConverterInterface
?
Спасибо.