I'm using ApiPlatform and Symfony5
I placed a filter on the User entity to sort them by a boolean value of the class named $expose
Use case:
- For the
/users?expose=truerouteROLE_USERcan get list of everyuserwith filter$exposeset totrue - For the
/users/routeROLE_ADMINcan get list of everyuserno matter what
Here is my User class:
/**
* @ApiResource(
* attributes={
* "normalization_context"={"groups"={"user:read", "user:list"}},
* "order"={"somefield.value": "ASC"}
* },
* collectionOperations={
* "get"={
* "mehtod"="GET",
* "security"="is_granted('LIST', object)",
* "normalization_context"={"groups"={"user:list"}},
* }
* }
* )
* @ApiFilter(ExistsFilter::class, properties={"expose"})
* @ApiFilter(SearchFilter::class, properties={
* "somefield.name": "exact"
* })
* @ORM\Entity(repositoryClass=UserRepository::class)
*/
I implement my authorization rules through UserVoter:
protected function supports($attribute, $subject): bool
{
return parent::supports($attribute, $subject) &&
($subject instanceof User ||
$this->arrayOf($subject, User::class) ||
(is_a($subject, Paginator::class) &&
$this->arrayOf($subject->getQuery()->getResult(), User::class))
);
}
protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
{
/** @var User $user */
$user = $token->getUser();
if (!$user instanceof User) {
return false;
}
if ($this->accessDecisionManager->decide($token, [GenericRoles::ROLE_ADMIN])) {
return true;
}
switch ($attribute) {
case Actions::LIST:
break;
}
return false;
}
To recover the list of User I recover the paginator object passed through the LIST attribute and make sure the object inside the request result are of type User.
This part have been tested and work properly.
Now my issue come from the fact that both those route are essentialy the same to my voter, so my authorization rules implemented through it apply to them both.
What I would like to do would be to tell my voter that both request are different (which I thought I could do as I recover a Paginator object but doesn't seem possible) so I can treat them separately in the same switch case.
So far I havn't found a way to implement it
Is there a way to implement this kind of rules ?
Or is there another way to implement this kind of authorization ?
Thank you!
If you can live with ordinary users and admin users using the same request
/users/but getting different results, this docs page describes a way to make the result of GET collection operations depend on the user that is logged in. I adapted it for your question:BTW, any users that do not have ROLE_ADMIN will get the filtered result, ROLE_USER is not required.