Restreindre l'ajout d'un message
A ce stade, si nous utilisons la route POST discussions/{id}/messages
nous pouvons écrire sur n'importe qu'elle Discussion. Nous allons restreindre l'écriture à l'auteur ou au participant.
Nous allons créer un Voter que nous appellerons dans notre CreateMessageInputDataPersister.
<?php
// src/Security/Voter/DiscussionVoter.php
use App\Entity\Discussion;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\User\UserInterface;
class DiscussionVoter extends Voter
{
protected function supports($attribute, $subject)
{
return in_array($attribute, ['MESSAGE_CREATE'])
&& $subject instanceof \App\Entity\Discussion;
}
/**
* @param $attribute
* @param Discussion $subject
* @param TokenInterface $token
* @return false
*/
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
$user = $token->getUser();
// if the user is anonymous, do not grant access
if (!$user instanceof UserInterface) {
return false;
}
switch ($attribute) {
case 'MESSAGE_CREATE':
if ($subject->getAuthor() === $user) {
return true;
}
if ($subject->isUserInParticipant($user)) {
return true;
}
break;
}
return false;
}
}
Dans ce voter on envoie la Discussion dans $subject
. On regarde ensuite si on est auteur de la Discussion ou si on fait partie des participants, si l'un des deux est vrai alors on peut enregistrer notre Message.
Nous avons besoin de créer une nouvelle méthode qui vérifie si on est dans les participants. Cette méthode sera sur l'entité Discussion
public function isUserInParticipant(User $user): bool
{
return $this->getParticipants()->contains($user);
}
``
Maintenant on se rend dans notre CreateMessageInputDataPersister pour appeler notre Voter en utilisant AuthorizationCheckerInterface
```php
<?php
namespace App\DataPersister;
use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
use App\Entity\Message;
use App\Repository\DiscussionRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Security;
class CreateMessageInputDataPersister implements ContextAwareDataPersisterInterface
{
/**
* @var RequestStack
*/
private $requestStack;
/**
* @var DiscussionRepository
*/
private $discussionRepository;
/**
* @var EntityManagerInterface
*/
private $entityManager;
/**
* @var Security
*/
private $security;
/**
* @var AuthorizationCheckerInterface
*/
private $authorizationChecker;
public function __construct(
RequestStack $requestStack,
DiscussionRepository $discussionRepository,
EntityManagerInterface $entityManager,
Security $security,
AuthorizationCheckerInterface $authorizationChecker
)
{
$this->requestStack = $requestStack;
$this->discussionRepository = $discussionRepository;
$this->entityManager = $entityManager;
$this->security = $security;
$this->authorizationChecker = $authorizationChecker;
}
public function supports($data, array $context = []): bool
{
return $data instanceof Message
&& (array_key_exists('collection_operation_name', $context)
&& $context['collection_operation_name'] === 'createNewMessage');
}
/**
* @param Message $data
* @param array $context
* @return void
*/
public function persist($data, array $context = [])
{
$user = $this->security->getUser();
$id = $this->requestStack->getMasterRequest()->attributes->get('id');
$discusssion = $this->discussionRepository->find($id);
if (!$this->authorizationChecker->isGranted('MESSAGE_CREATE', $discusssion)) {
throw new AccessDeniedException();
}
$data->setDiscussion($discusssion);
$data->setAuthor($user);
$this->entityManager->persist($data);
$this->entityManager->flush();
return $data;
}
public function remove($data, array $context = [])
{
}
}
Avec la méthode isGranted
on regarde si on à accès à cette Discussion, si oui on enregistre notre Message, si non alors Access Denied.
est retourné avec une Réponse 403
Commentaires
Connectez-vous pour laisser un commentaire