Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.7k
[Security] Cache voters that will always abstain#43066
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
ro0NL commentedSep 16, 2021 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Should we explore dedicated PHP8 class attributes? IIUC eg. |
nicolas-grekas commentedSep 17, 2021
I don't know if we need an attribute for that, but what about a method that exposes what a voter cares about@jderusse, instead of the current approach? |
stof commentedSep 17, 2021
@jderusse what about voters that vote only on |
ro0NL commentedSep 17, 2021 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@nicolas-grekas i generally like attributes enforcing static/cachable rules to us :) but runtime api also fits yes. As an end user taking care of such issues, an attribute looks elegant IMHO. |
stof commentedSep 17, 2021
An attribute might make the architecture of the AccessDecisionManager harder, if we want to avoid calling Reflection on each |
ro0NL commentedSep 17, 2021 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Understood. I meant levaraging DI at compile time. Writing another set of support method implementations already bugs/confuses me somewhat. But it'll be the edge case... WFM. |
jderusse commentedSep 17, 2021
Yeah, I hesitated with this approach: but it can not work for voters that use a pattern for attributes: ie RoleVoter =>
This will work: the current approach is to let voters reporting "I will alwaysabstain for this attribute" and/or "I will alwaysabstain for this object", everything else will always be called. If voters don't care about subjects (like RoleVoter) they can return The code will still be optimized because the voter will not be called when the attribute does not start with note: to be accurate RoleVoter does not vote "only on null subject", they vote on "whatever the content of the subject". |
nicolas-grekas left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
LGTM, except the naming :)
What aboutCacheableVoterInterface withsupportsAttribute() andsupportsType() methods?
src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
src/Symfony/Component/Security/Core/Authorization/Voter/CacheableAbstainVotesInterface.php OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
jderusse commentedOct 20, 2021
Cmments addressed, and tests added |
nicolas-grekas left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
2 comments + fabbot and good to me!
src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
2d557cc to6508fbbComparesrc/Symfony/Component/Security/Core/Authorization/Voter/CacheableVoterInterface.php OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
33390fe toef8f125Compare
nicolas-grekas left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
found some typos, but still 👍 on my side
/cc @symfony/mergers
src/Symfony/Component/Security/Core/Authorization/Voter/CacheableVoterInterface.php OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
src/Symfony/Component/Security/Core/Authorization/Voter/CacheableVoterInterface.php OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
lyrixx left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
One minor comment, otherwise 👍🏼 thanks !
src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.phpShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
fabpot commentedOct 28, 2021
Thank you@jderusse. |
dkarlovi commentedNov 4, 2021
With the renaming of the interface and methods, the semantics seem reversed when you first look at it. Since the interface is now called |
stof commentedNov 4, 2021
|
dkarlovi commentedNov 4, 2021
@stof in that case the interface is misnamed, IMO, the original names seem more appropriate. |
nicolas-grekas commentedNov 4, 2021
The original names were confusing to me. Feels like double negation: I'm not against renaming |
dkarlovi commentedNov 4, 2021
It depends who gets to define "better". As I said, the weird part here is returning |
jderusse commentedNov 4, 2021
thing is, the feature is about improving performance when somethingIS NOT able to process the payload. Having a negation will always be confusing. One could use In my opinion If we need to change something it should be the name of the interface. Would be happy to make a PR if somebody have a suggestion. |
javiereguiluz commentedNov 4, 2021 • edited by nicolas-grekas
Loading Uh oh!
There was an error while loading.Please reload this page.
edited by nicolas-grekas
Uh oh!
There was an error while loading.Please reload this page.
I'm on a phone so I can't explain on detail, but to me the current implementation is very intuitive because I understand it as follows: Symfony: Hey voter, do you support ARTICLE_EDIT attribute? |
dkarlovi commentedNov 4, 2021 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
This means the voter cacheability is a side-effect of this detection, it's inferred and not directly stated. Your votes is not becoming "cacheable", it's becoming "more capable of explaining what it knows how to work with".. which is the information then used to make it cacheable. It basically has "extended / detailed supports" support. |
wouterj commentedNov 4, 2021
I must say that I quite liked the That said, this little nuance can be fulfilled easily by documentation. |
The current implementation of the AccessDecisionManager is to iterate over all the Voters, and stops when the strategy is met.
When an application performs a lot of checks (ie. an Admin shows a list of "blog post" and shows buttons to users that are allowed to "edit", "delete", "publish", ... ie
{% if is_granted('blog_delete', item) %}DELETE{% endif %}). In that case, the number of calls to theVoterInterface::votemethods grows exponentially. At some point, adding a new Voter to handle a new case (maybe not related to our blog posts) will have a performance impactMoreover in most of the time, a voter looks like:
We could leverage this, to cache the list of voters that need to be called or can be ignored
In the same way
symfony/serializerprovides aCacheableSupportsMethodInterfaceI suggest to add a newCacheableAbstainVotesInterfacethat will remember voters that will always abstain vote on a given attribute or a given object's typeWhen the Voter does not implements the interface OR returns
falsewill provide the current behavior: The voter is always called.How to use this PR:
Results:
For 40 Voters and calling 500 times
isGranted(variousAttributes, variousObjects)it get -40% perf gain !Opinionated choices in that PR:
TODO