I have a voter that checks if user can edit a document, the rules are either user owns document or user is a super admin, to check ownership of document the document Entity first has to be fetched. This I managed without any problem.
But it seems that I have to add:
$this->denyAccessUnlessGranted('edit', $doc);
to about 7 methods in my controller, is there a more efficient way of doing this?
I thought of using Kernel Event, but putting this check in event subscriber doesn't do much, because I don't see any way to influence further code execution. And if I throw uncaught exception whole Symfony will crash. No matter what I do, the called method will be executed... But then I might as well just edit every method. I don't want to repeat this piece of code everywhere but it seems I don't have another option.
It will depend on where you are getting $doc
. You can put a @Security annotation (or @IsGranted("do-stuff-with-doc")
) onto the class itself to allow, or deny, access to all the actions in it (this does presume that just the 7 actions you want to protect are in the same class).
With a voter checking access for the current user on the permission called "do-stuff-with-doc", since that will also be a service, it's got access to all the other services you care to inject, and the $request that is about to be injected into the appropriate actions (via RequestStack $reqstack; $currRequest = $reqstack->getCurrentRequest();
). In the current-request are the action's parameter, which would either have the $doc, or enough information you could probably get it.
From that, or other services you can auto-wire (or manually define to inject) into the voter, it's up to you to how, or why a user has access to whatever.
class DoDocStuffVoter extends Voter
{
public function __construct(RequestStack $reqStack)
{
$this->reqStack = $reqStack;
// and other services you want to add
}
public function supports($attribute, $subject)
{
return $attribute === 'do-stuff-with-doc';
}
protected function voteOnAttribute($attribute, $object, TokenInterface $token): bool
{
$user = $token->getUser();
$request = $this->reqStack->getCurrentRequest();
dump($user, $request);
die;
// does someone with this request get access to doc?
return $this->userHasAccessToDoc($user, $request);
}
}