简体   繁体   English

ManyToMany itemOperations“access_control”

[英]ManyToMany itemOperations "access_control"

Thats the code from the docu那是文档中的代码

// https://api-platform.com/docs/core/security/#security
itemOperations={
     "get"={"access_control"="is_granted('ROLE_USER') and object.owner == user"}
 }

how can i get that realized with many to many, i tried many different expressions but everytime i get a error.我怎样才能实现多对多,我尝试了许多不同的表达方式,但每次我都会出错。

<?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;

    // ...
}

nYou cant in those cases where the target relation is a collection. 你不能在目标关系是集合的情况下。 In this case, users collection. 在这种情况下,用户收集。

For these cases, you should create a subscriber with PRE_SERIALIZE event and throw Access Denied exception there. 对于这些情况,您应该创建一个具有PRE_SERIALIZE事件的订户,并在那里抛出Access Denied exception。

You have to do something like this. 你必须做这样的事情。 As you say you have a ManyToMany relation, I guess that you have an intermediate entity between book and user, so you should use that repository for find user <-> book then. 正如你所说你有一个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();
    }
}

Here is something I did for a resource that is ManytoOne related to intermediate entity Events ManytoOne related to one Organizer, with Users ManyToMany related to Organizers (collection).这是我为 ManytoOne 资源所做的事情,该资源与中间实体 Events ManytoOne 与一个组织者相关,用户 ManyToMany 与组织者(集合)相关。

I transform the collection to Array and use "in" operator to compare data.我将集合转换为数组并使用“in”运算符来比较数据。 For a more sophisticated operation you should look at Doctrine Extension as it's describe in API Platform doc.对于更复杂的操作,您应该查看 Doctrine 扩展,如 API 平台文档中所述。

#[ApiResource(
    operations: [
        new GetCollection(),
        new Post(),
        new Get(security: "object.getEvent().getOrganizer() in user.getOrganizers().toArray()"),
        new Patch(),
        new Delete()
    ]
)]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM