Security voters are one of Symfony's most powerful tools for managing permissions. They let you centralize your authorization logic and reuse it throughout your application. In Symfony 7.4, we're introducing several new features for them.
Twig Functions for Access Decisions
Symfony already provides the is_granted()
and is_granted_for_user()
Twig functions so you can check permissions with voters in your templates.
These functions return a boolean value indicating whether the current or
specified user has the given security attribute.
In Symfony 7.4, we're adding two new Twig functions: access_decision()
and
access_decision_for_user()
. They return an AccessDecision object, a DTO
that stores the access verdict, the collection of votes, the resulting message
(for example, "Access granted" or a custom access-denied message), and more.
1 2 3 4 5 6 7
{% set voter_decision = access_decision('post_edit', post) %}
{% if voter_decision.isGranted() %}
{# ... #}
{% else %}
{# before showing voter messages to end users, make sure it's safe to do so #}
<p>{{ voter_decision.message }}</p>
{% endif %}
Add Metadata to Vote Objects
In Symfony 7.3, we introduced the Vote
object as part of a feature that
explains security voter decisions. In Symfony 7.4, we're extending it so you can
attach arbitrary metadata to each vote. Inside your security voter, use the
extraData
property of the Vote
object to add any custom value:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
use Symfony\Component\Security\Core\Authorization\Voter\Vote;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
// ...
class BlogPostVoter extends Voter
{
// ...
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool
{
// ...
// values can be of any type, not only strings
$vote->extraData['some_key'] = 'some value';
}
}
You can use this new feature, for example, when defining a custom access decision strategy.
By default, Symfony votes can only grant, deny, or abstain, and all votes
have equal weight. In a custom strategy, you could assign a score or weight to
each vote (for example, $vote->extraData['score'] = 10;
) and use that value
when aggregating results:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
// src/Security/MyCustomAccessDecisionStrategy.php
use Symfony\Component\Security\Core\Authorization\Strategy\AccessDecisionStrategyInterface;
class MyCustomAccessDecisionStrategy implements AccessDecisionStrategyInterface
{
public function decide(\Traversable $results, $accessDecision = null): bool
{
$score = 0;
foreach ($results as $key => $result) {
$vote = $accessDecision->votes[$key];
if (array_key_exists('score', $vote->extraData)) {
$score += $vote->extraData['score'];
} else {
$score += $vote->result;
}
}
// ...
}
}