Skip to content

Commit 523229b

Browse files
committed
minor #20690 [Security] Add ability for voters to explain their vote (MrYamous)
This PR was squashed before being merged into the 7.3 branch. Discussion ---------- [Security] Add ability for voters to explain their vote Fix #20658 Commits ------- 203c0f8 [Security] Add ability for voters to explain their vote
2 parents 2ecb02e + 203c0f8 commit 523229b

File tree

2 files changed

+30
-8
lines changed

2 files changed

+30
-8
lines changed

security.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2694,13 +2694,14 @@ anonymous users access by checking if there is no user set on the token::
26942694
// ...
26952695
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
26962696
use Symfony\Component\Security\Core\Authentication\User\UserInterface;
2697+
use Symfony\Component\Security\Core\Authorization\Voter\Vote;
26972698
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
26982699

26992700
class PostVoter extends Voter
27002701
{
27012702
// ...
27022703

2703-
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
2704+
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token, ?Vote $vote = null): bool
27042705
{
27052706
// ...
27062707

@@ -2712,6 +2713,11 @@ anonymous users access by checking if there is no user set on the token::
27122713
}
27132714
}
27142715

2716+
.. versionadded:: 7.3
2717+
2718+
The `$vote` parameter in the :method:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::voteOnAttribute` method
2719+
was introduced in Symfony 7.3.
2720+
27152721
Setting Individual User Permissions
27162722
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27172723

security/voters.rst

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,20 @@ or extend :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\Vote
4040
which makes creating a voter even easier::
4141

4242
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
43+
use Symfony\Component\Security\Core\Authorization\Voter\Vote;
4344
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
4445

4546
abstract class Voter implements VoterInterface
4647
{
4748
abstract protected function supports(string $attribute, mixed $subject): bool;
48-
abstract protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool;
49+
abstract protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool;
4950
}
5051

52+
.. versionadded:: 7.3
53+
54+
The `$vote` parameter in the :method:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::voteOnAttribute` method
55+
was introduced in Symfony 7.3.
56+
5157
.. _how-to-use-the-voter-in-a-controller:
5258

5359
.. tip::
@@ -140,6 +146,7 @@ would look like this::
140146
use App\Entity\Post;
141147
use App\Entity\User;
142148
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
149+
use Symfony\Component\Security\Core\Authorization\Voter\Vote;
143150
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
144151

145152
class PostVoter extends Voter
@@ -163,12 +170,14 @@ would look like this::
163170
return true;
164171
}
165172

166-
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
173+
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool
167174
{
168175
$user = $token->getUser();
176+
$vote ??= new Vote();
169177

170178
if (!$user instanceof User) {
171179
// the user must be logged in; if not, deny access
180+
$vote->reasons[] = 'The user is not logged in.';
172181
return false;
173182
}
174183

@@ -197,7 +206,13 @@ would look like this::
197206
private function canEdit(Post $post, User $user): bool
198207
{
199208
// this assumes that the Post object has a `getOwner()` method
200-
return $user === $post->getOwner();
209+
if ($user === $post->getOwner()) {
210+
return true;
211+
}
212+
213+
$vote->reasons[] = 'You are not the owner of the Post.';
214+
215+
return false;
201216
}
202217
}
203218

@@ -215,11 +230,12 @@ To recap, here's what's expected from the two abstract methods:
215230
return ``true`` if the attribute is ``view`` or ``edit`` and if the object is
216231
a ``Post`` instance.
217232

218-
``voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token)``
233+
``voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null)``
219234
If you return ``true`` from ``supports()``, then this method is called. Your
220235
job is to return ``true`` to allow access and ``false`` to deny access.
221-
The ``$token`` can be used to find the current user object (if any). In this
222-
example, all of the complex business logic is included to determine access.
236+
The ``$token`` can be used to find the current user object (if any). The ``$vote``
237+
argument can be used to add a reason to the vote. In this example, all of the
238+
complex business logic is included to determine access.
223239

224240
.. _declaring-the-voter-as-a-service:
225241

@@ -256,7 +272,7 @@ with ``ROLE_SUPER_ADMIN``::
256272
) {
257273
}
258274

259-
protected function voteOnAttribute($attribute, mixed $subject, TokenInterface $token): bool
275+
protected function voteOnAttribute($attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool
260276
{
261277
// ...
262278

0 commit comments

Comments
 (0)