Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1f4e591

Browse filesBrowse files
committed
Cache voters that will always abstain
1 parent c0bf036 commit 1f4e591
Copy full SHA for 1f4e591

File tree

5 files changed

+101
-7
lines changed
Filter options

5 files changed

+101
-7
lines changed

‎src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php
+35-4Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace Symfony\Component\Security\Core\Authorization;
1313

1414
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
15+
use Symfony\Component\Security\Core\Authorization\Voter\CacheableAbstainOnAttributes;
16+
use Symfony\Component\Security\Core\Authorization\Voter\CacheableAbstainVotesInterface;
1517
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
1618
use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
1719

@@ -29,6 +31,8 @@ class AccessDecisionManager implements AccessDecisionManagerInterface
2931
public const STRATEGY_PRIORITY = 'priority';
3032

3133
private $voters;
34+
private $votersCacheAttributes;
35+
private $votersCacheObject;
3236
private $strategy;
3337
private $allowIfAllAbstainDecisions;
3438
private $allowIfEqualGrantedDeniedDecisions;
@@ -80,7 +84,7 @@ public function decide(TokenInterface $token, array $attributes, $object = null/
8084
private function decideAffirmative(TokenInterface $token, array $attributes, $object = null): bool
8185
{
8286
$deny = 0;
83-
foreach ($this->voters as $voter) {
87+
foreach ($this->getVoters($attributes, $object) as $voter) {
8488
$result = $voter->vote($token, $object, $attributes);
8589

8690
if (VoterInterface::ACCESS_GRANTED === $result) {
@@ -119,7 +123,7 @@ private function decideConsensus(TokenInterface $token, array $attributes, $obje
119123
{
120124
$grant = 0;
121125
$deny = 0;
122-
foreach ($this->voters as $voter) {
126+
foreach ($this->getVoters($attributes, $object) as $voter) {
123127
$result = $voter->vote($token, $object, $attributes);
124128

125129
if (VoterInterface::ACCESS_GRANTED === $result) {
@@ -155,7 +159,7 @@ private function decideConsensus(TokenInterface $token, array $attributes, $obje
155159
private function decideUnanimous(TokenInterface $token, array $attributes, $object = null): bool
156160
{
157161
$grant = 0;
158-
foreach ($this->voters as $voter) {
162+
foreach ($this->getVoters($attributes, $object) as $voter) {
159163
foreach ($attributes as $attribute) {
160164
$result = $voter->vote($token, $object, [$attribute]);
161165

@@ -188,7 +192,7 @@ private function decideUnanimous(TokenInterface $token, array $attributes, $obje
188192
*/
189193
private function decidePriority(TokenInterface $token, array $attributes, $object = null)
190194
{
191-
foreach ($this->voters as $voter) {
195+
foreach ($this->getVoters($attributes, $object) as $voter) {
192196
$result = $voter->vote($token, $object, $attributes);
193197

194198
if (VoterInterface::ACCESS_GRANTED === $result) {
@@ -206,4 +210,31 @@ private function decidePriority(TokenInterface $token, array $attributes, $objec
206210

207211
return $this->allowIfAllAbstainDecisions;
208212
}
213+
214+
private function getVoters(array $attributes, $object = null): iterable
215+
{
216+
$keyAttributes = count($attributes) === 1 && is_string($attributes[0]) ? $attributes[0] : null;
217+
$keyObject = get_debug_type($object);
218+
219+
foreach ($this->voters as $key => $voter) {
220+
if (!isset($this->votersCacheAttributes[$keyAttributes][$key])) {
221+
$this->votersCacheAttributes[$keyAttributes][$key] = $willAbstain = $voter instanceof CacheableAbstainVotesInterface && ($keyAttributes === null || $voter->willAlwaysAbstainOnAttribute($keyAttributes));
222+
} else {
223+
$willAbstain = $this->votersCacheAttributes[$keyAttributes][$key];
224+
}
225+
if ($willAbstain) {
226+
continue;
227+
}
228+
229+
if (!isset($this->votersCacheObject[$keyObject][$key])) {
230+
$this->votersCacheObject[$keyObject][$key] = $willAbstain = $voter instanceof CacheableAbstainVotesInterface && $voter->willAlwaysAbstainOnObjectType($keyObject);
231+
} else {
232+
$willAbstain = $this->votersCacheObject[$keyObject][$key];
233+
}
234+
if ($willAbstain) {
235+
continue;
236+
}
237+
yield $voter;
238+
}
239+
}
209240
}

‎src/Symfony/Component/Security/Core/Authorization/Voter/AuthenticatedVoter.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Core/Authorization/Voter/AuthenticatedVoter.php
+17-1Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
* @author Fabien Potencier <fabien@symfony.com>
2525
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
2626
*/
27-
class AuthenticatedVoter implements VoterInterface
27+
class AuthenticatedVoter implements VoterInterface, CacheableAbstainVotes
2828
{
2929
public const IS_AUTHENTICATED_FULLY = 'IS_AUTHENTICATED_FULLY';
3030
public const IS_AUTHENTICATED_REMEMBERED = 'IS_AUTHENTICATED_REMEMBERED';
@@ -116,4 +116,20 @@ public function vote(TokenInterface $token, $subject, array $attributes)
116116

117117
return $result;
118118
}
119+
120+
public function willAlwaysAbstainOnAttribute(string $attribute): bool
121+
{
122+
return self::IS_AUTHENTICATED_FULLY !== $attribute
123+
&& self::IS_AUTHENTICATED_REMEMBERED !== $attribute
124+
&& self::IS_AUTHENTICATED_ANONYMOUSLY !== $attribute
125+
&& self::IS_ANONYMOUS !== $attribute
126+
&& self::IS_IMPERSONATOR !== $attribute
127+
&& self::IS_REMEMBERED !== $attribute
128+
&& self::PUBLIC_ACCESS !== $attribute;
129+
}
130+
131+
public function willAlwaysAbstainOnObjectType(string $objectType): bool
132+
{
133+
return false;
134+
}
119135
}
+27Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Security\Core\Authorization\Voter;
13+
14+
/**
15+
* Marker interface for voters that know if they will always abstain for the
16+
* give attributes.
17+
*
18+
* By implementing this interface, the voter will never be called for the
19+
* specified attributes.
20+
*
21+
* @author Jérémy Derussé <jeremy@derusse.com>
22+
*/
23+
interface CacheableAbstainVotesInterface
24+
{
25+
public function willAlwaysAbstainOnAttribute(string $attribute): bool;
26+
public function willAlwaysAbstainOnObjectType(string $objectType): bool;
27+
}

‎src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php
+11-1Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*
1919
* @author Fabien Potencier <fabien@symfony.com>
2020
*/
21-
class RoleVoter implements VoterInterface
21+
class RoleVoter implements VoterInterface, CacheableAbstainVotes
2222
{
2323
private $prefix;
2424

@@ -55,6 +55,16 @@ public function vote(TokenInterface $token, $subject, array $attributes)
5555
return $result;
5656
}
5757

58+
public function willAlwaysAbstainOnAttribute(string $attribute): bool
59+
{
60+
return !str_starts_with($attribute, $this->prefix);
61+
}
62+
63+
public function willAlwaysAbstainOnObjectType(string $objectType): bool
64+
{
65+
return false;
66+
}
67+
5868
protected function extractRoles(TokenInterface $token)
5969
{
6070
return $token->getRoleNames();

‎src/Symfony/Component/Security/Core/Authorization/Voter/TraceableVoter.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Core/Authorization/Voter/TraceableVoter.php
+11-1Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
*
2323
* @internal
2424
*/
25-
class TraceableVoter implements VoterInterface
25+
class TraceableVoter implements VoterInterface, CacheableAbstainVotes
2626
{
2727
private $voter;
2828
private $eventDispatcher;
@@ -46,4 +46,14 @@ public function getDecoratedVoter(): VoterInterface
4646
{
4747
return $this->voter;
4848
}
49+
50+
public function willAlwaysAbstainOnAttribute(string $attribute): bool
51+
{
52+
return $this->voter instanceof CacheableAbstainVotesInterface && $this->voter->willAlwaysAbstainOnAttribute($attribute);
53+
}
54+
55+
public function willAlwaysAbstainOnObjectType(string $objectType): bool
56+
{
57+
return $this->voter instanceof CacheableAbstainVotesInterface && $this->voter->willAlwaysAbstainOnObjectType($objectType);
58+
}
4959
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.