I am using security voters as alternative to symfony's acl system.
my voters look similar go the following one.
class FoobarVoter implements VoterInterface
{
public function supportsClass($class)
{
return in_array($class, array(
'Example\FoobarBundle\Entity\Foobar',
));
}
public function supportsAttribute($attribute)
{
return in_array(strtolower($attribute), array('foo', 'bar'));
}
public function vote(TokenInterface $token, $object, array $attributes)
{
$result = VoterInterface::ACCESS_ABSTAIN
if (!$this->supportsClass(get_class($object))) {
return VoterInterface::ACCESS_ABSTAIN;
}
foreach ($attributes as $attribute) {
$attribute = strtolower($attribute);
// skip not supported attributes
if (!$this->supportsAttribute($attribute)) {
continue;
}
[... some logic ...]
}
return $result;
}
}
my voters are included and called on every page load. even if they do not support decisions for a given class. FoobarVoter::vote()
is always called. even if FoobarVoter::supportsClass()
or FoobarVoter::supportsAttribute
return false. thus i need to check class and attribute inside FoobarVoter::vote()
. is this behaviour standard? how can i prevent this unnecessary call.
some voters are only needed inside specific bundles. some are only needed to decide about specific classes. thus some voters are not needed in all parts of my application. is it possible to include voters per bundle/entity dynamically? e.g. only include voters into decision manager chain if a specific bundle or a specific entity is accessed/used?
Voters are Symfony's most powerful way of managing permissions. They allow you to centralize all permission logic, then reuse them in many places.
Symfony provides many tools to secure your application. Some HTTP-related security tools, like secure session cookies and CSRF protection are provided by default. The SecurityBundle, which you will learn about in this guide, provides all authentication and authorization features needed to secure your application.
Looking through the source code of Symfony, it appears to be because the AccessDecisionManager
uses those methods (supportsClass and seupportsAttribute) to roll-up support to itself.
What this allows your voter to do is extend the cases when the manager will be applied. So you're not detailing the capability of your voter, but of the entire voting process. Whether or not that's what you want is something else...
As far as reducing the un-necessary calls, it's not un-necessary in the general case. The system is designed using one of three methods:
Allow based (decideAffirmative
). This uses an "allow based" voting. Which means that if one plugin says "allow" then you're allowed.
Concensus Based (decideConsensus
). This uses a concensus based permission, where if more voters agree to allow than to deny you're allowed...
Deny Based (decideUnanimous
). This uses a "deny based" voting. Which means that if one plugin says "deny", then you're denied. Otherwise you need at least one grant.
So considering that all of them rely on the explicit Deny vs Allow, running all of the plugins for every request actually makes sense. Because even if you don't specifically support a class, you may want to allow or deny that request.
In short, there's not much to gain by limiting the voters by the supports attributes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With