多对多项目操作 "access_control"
ManyToMany itemOperations "access_control"
这是文档中的代码
// https://api-platform.com/docs/core/security/#security
itemOperations={
"get"={"access_control"="is_granted('ROLE_USER') and object.owner == user"}
}
我如何通过多对多实现这一点,我尝试了很多不同的表达方式,但每次都会出错。
<?php
// api/src/Entity/Book.php
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Secured resource.
*
* @ApiResource(
* itemOperations={
* "get"={"access_control"="is_granted('ROLE_USER') and object.users == user"}
* }
* )
* @ORM\Entity
*/
class Book
{
// ...
/**
* @var User The owner
*
* @ORM\ManyToMany(targetEntity="App\Entity\User", mappedBy="book", cascade={"persist"})
*/
public $users;
// ...
}
n在目标关系是集合的情况下,您不能这样做。在这种情况下,用户集合。
对于这些情况,您应该使用 PRE_SERIALIZE 事件创建一个订阅者并在那里抛出拒绝访问异常。
你必须做这样的事情。正如你所说的你有一个 ManyToMany 关系,我猜你在 book 和 user 之间有一个中间实体,所以你应该使用那个存储库来查找用户 <-> book 然后。
<?php
namespace App\EventSubscriber;
use ApiPlatform\Core\EventListener\EventPriorities;
use App\Entity\User;
use App\Entity\Book;
use App\Repository\UserRepository;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
class ChatMessagePreSerializeSubscriber implements EventSubscriberInterface
{
private $tokenStorage;
private $userRepository;
private $authorizationChecker;
public function __construct(
TokenStorageInterface $tokenStorage,
UserRepository $userRepository,
AuthorizationCheckerInterface $authorizationChecker
) {
$this->tokenStorage = $tokenStorage;
$this->userRepository = $userRepository;
$this->authorizationChecker = $authorizationChecker;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
{
return [
KernelEvents::VIEW => ['bookPreSerialize', EventPriorities::PRE_SERIALIZE],
];
}
public function bookPreSerialize(GetResponseForControllerResultEvent $event)
{
$book = $event->getControllerResult();
$method = $event->getRequest()->getMethod();
if (!$book instanceof Book || (Request::METHOD_GET !== $method)) {
return;
}
$currentUser = $this->tokenStorage->getToken()->getUser();
if (!$currentUser instanceof User)
return;
$user = $this->userRepository->findOneBy(['id' => $currentUser->getId(), 'book' => $book]);
if (!$user instanceof User)
throw new AccessDeniedHttpException();
}
}
这是文档中的代码
// https://api-platform.com/docs/core/security/#security
itemOperations={
"get"={"access_control"="is_granted('ROLE_USER') and object.owner == user"}
}
我如何通过多对多实现这一点,我尝试了很多不同的表达方式,但每次都会出错。
<?php
// api/src/Entity/Book.php
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Secured resource.
*
* @ApiResource(
* itemOperations={
* "get"={"access_control"="is_granted('ROLE_USER') and object.users == user"}
* }
* )
* @ORM\Entity
*/
class Book
{
// ...
/**
* @var User The owner
*
* @ORM\ManyToMany(targetEntity="App\Entity\User", mappedBy="book", cascade={"persist"})
*/
public $users;
// ...
}
n在目标关系是集合的情况下,您不能这样做。在这种情况下,用户集合。
对于这些情况,您应该使用 PRE_SERIALIZE 事件创建一个订阅者并在那里抛出拒绝访问异常。
你必须做这样的事情。正如你所说的你有一个 ManyToMany 关系,我猜你在 book 和 user 之间有一个中间实体,所以你应该使用那个存储库来查找用户 <-> book 然后。
<?php
namespace App\EventSubscriber;
use ApiPlatform\Core\EventListener\EventPriorities;
use App\Entity\User;
use App\Entity\Book;
use App\Repository\UserRepository;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
class ChatMessagePreSerializeSubscriber implements EventSubscriberInterface
{
private $tokenStorage;
private $userRepository;
private $authorizationChecker;
public function __construct(
TokenStorageInterface $tokenStorage,
UserRepository $userRepository,
AuthorizationCheckerInterface $authorizationChecker
) {
$this->tokenStorage = $tokenStorage;
$this->userRepository = $userRepository;
$this->authorizationChecker = $authorizationChecker;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
{
return [
KernelEvents::VIEW => ['bookPreSerialize', EventPriorities::PRE_SERIALIZE],
];
}
public function bookPreSerialize(GetResponseForControllerResultEvent $event)
{
$book = $event->getControllerResult();
$method = $event->getRequest()->getMethod();
if (!$book instanceof Book || (Request::METHOD_GET !== $method)) {
return;
}
$currentUser = $this->tokenStorage->getToken()->getUser();
if (!$currentUser instanceof User)
return;
$user = $this->userRepository->findOneBy(['id' => $currentUser->getId(), 'book' => $book]);
if (!$user instanceof User)
throw new AccessDeniedHttpException();
}
}