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=true
routeROLE_USER
can get list of everyuser
with filter$expose
set totrue
- For the
/users/
routeROLE_ADMIN
can get list of everyuser
no 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.