Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

annotations - ApiPlatform - collectionOperations not passing support method on voter

I use Symfony5 with ApiPlaform

I'm stuck on a litlle issue but I can't find any materials to get me through it

So, I have an entity open to the API from which I want to recover a list of

Naturally I set up collectionOperations like so :

 *     collectionOperations={
 *          "get"={
 *              "mehtod"="GET",
 *              "security"="is_granted('LIST', object)",
 *              "normalization_context"={"groups"={"user:list"}},
 *          }
 *     },

And check inside my voter on the supports method like that :

    protected function supports($attribute, $subject): bool
    {
        return parent::supports($attribute, $subject)
            && (
                $subject instanceof User
                || $this->arrayOf($subject, User::class)
            );
    }

I thought the arrayOf condition would check for list of object, but I receive a pagination object, and therefore can only check if it's a pagination object, which could create issues with my other voters. And anyway just return my a Paginator object in the voteOnAttribute method (already tried)

So my question is, is there a way to check for authorization on list of object by sending the object from the annotations to the voter ?

Thanks !


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

collection operation will not pass your User::class. (It will probably pass sth. like Paginator).

Way 1: Filter your collection

You can filter your collection by changing query-builder for Users. see https://api-platform.com/docs/core/extensions/

Way 2: Custom normalizer

You can check for security in custom normalizer and change serialization_context or throw an exception if user does not have access for object. This method can have negative influence on performance.

https://api-platform.com/docs/core/serialization/#changing-the-serialization-context-on-a-per-item-basis

Here is example of my normalizer

Normalize method:


    public function normalize($object, string $format = null, array $context = []): array
    {
        $context['groups'] = []; //remove all groups
        $context['groups'][] = 'read:always';
        
        if ($this->security->isGranted('ENTITY_ACCESS', $object)) {
            $context['groups'][] = 'read'; //allow to read properties with @Groups{{"read"}}
        } else {
            throw new ClientError(ClientErrorType::CHECK_ACCESS, ['type' => $this->getEntityName($object)]);
        }

        $context['groups'] = array_unique($context['groups']);
        $context['resource_normalizer_call_data'][] = $object->getId();
        return $this->normalizer->normalize($object, $format, $context);
    }

SupportsNormalization method

    public function supportsNormalization($data, string $format = null, array $context = []): bool
    {

        if ( //is object doctrine entity?
            !$this->isEntity($this->managerRegistry->getManager(), $data)
            || !isset($context['graphql_operation_name'])

        ) {
            return false;
        }

        if ( //dont normalize same entity twice! 
            isset($context['resource_normalizer_call_data'])
            && in_array($data->getId(), $context['resource_normalizer_call_data'])
        ) {
            return false;
        }

        return true;
    }


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...