-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[AccessControl] Add Access Control component with strategies and voters #59439
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 7.3
Are you sure you want to change the base?
Conversation
This comment has been minimized.
This comment has been minimized.
hello @Spomky 👋🏻 a bit unrelated to PR review, but still worth mentioning imho (feel free to hide the comment later) as you mentioned "and an optional reason" wdyt of cascading close perhaps all those PRs and issues (#58107 et al. originally from this) and ask ppl that may subscribe to those PR to come here reviews? |
One thing I think should be added here is a way to specify the user we're wanting to check authorization for like was added in #48142 as we won't always have a user session while dealing with authorization (console commands, messenger messages, etc) |
Introduce the new Access Control component in Symfony, providing core access decision-making and voting mechanisms. This includes support for affirmative, unanimous, and consensus strategies, along with role-based and expression-based voters. Tests and examples included to validate behavior.
Updated role extraction logic to accept more flexible subject types, including `TokenInterface`, `UserInterface`, and `UserWithRoleInterface`. Introduced a `getUser` helper method to streamline user retrieval from supported subjects. Enhanced code clarity and compatibility with diverse subject instances.
cd31fba
to
8a5587d
Compare
Hello @94noni, I love the idea. I will ping contributors of the other PRs/Issues to be part of this PR too.
Helli @natewiebe13, I changed to Role(Hierarchy)Voter to handle that. $accessDecision = $accessControlManager->decide(new AccessRequest(
'ROLE_xxx', // The security attribute
$subject // Can be null (current user, similar to what the attribute AccessPolicy('ROLE_xxx') does), a security token or a user object
)); |
@Spomky not exactly what I mean. For example, I may want to see if a specific user has publish access to a blog post. In that instance, the subject would be the blog post and the attribute would be something like |
Sorry, I answered a bit quickly. $accessDecision = $accessControlManager->decide(new AccessRequest(
'PUBLISH', // The security attribute
$post, // The subject
['target' => $user] // Arbitrary key here. Change 'target' with another key name. Shall be the same as the one used by the voter (btw use constant instead of hardcoded string)
)); The voter: <?php
namespace Acme\Voter;
final readonly class PublishBlogPostVoter implements VoterInterface
{
public function vote(AccessRequest $accessRequest): VoterOutcome
{
$target = $accessRequest->metadata['target'] ?? null;
//Check the target is valid. Throw an exception when required, return VoterOutcome::abstain('...') or use the current user depending on your application needs;
//Check if the user is granted or not and return VoterOutcome::deny('...') or VoterOutcome::grant('...');
}
public function supportsAttribute(mixed $attribute): bool
{
return $attribute === 'PUBLISH'; // Just for the example
}
public function supportsSubject(mixed $subject): bool
{
return $subject instanceof BlogPost; // Just for the example
}
} |
@Spomky I had a feeling that's what might be suggested. I'd argue that async is becoming more and more common, and at least for the projects I work on happen often enough, that there should be a more concrete mechanism, rather than arbitrary array keys. I'd personally prefer it if you had to explicitly set the target, then the component doesn't have to even consider sessions or assume that the target user is going to be set somehow. But that's likely a bit too extreme for some. Either way, I still like the idea of this component, just hope we get a more concrete way of specifying the target. |
I understand your concern, and honestly, I initially added a That said, I agree that having a more concrete and explicit way to set the target could simplify the logic and make the component more predictable, especially for common cases like direct user-to-resource access. |
Replaced reliance on `TokenStorageInterface` with requester tokens directly passed via `AccessRequest` objects. Introduced `MetadataBag` for improved metadata handling and marked several classes as `final`. Updated tests and strategies accordingly to simplify the architecture and enhance maintainability.
Introduce the new Access Control component in Symfony, providing core access decision-making and voting mechanisms. This includes support for affirmative, unanimous, and consensus strategies, along with role-based and expression-based voters. Tests and examples included to validate behavior.
Hi,
As I mentioned in the issue I submitted, I’m proposing a new component. Currently, it doesn’t do anything beyond what the existing access control feature in the security component already offers. It’s still in an early stage of exploration and development, so please don’t expect a fully functional component at this point.
The main goal is to remove the
getRoles()
method from the user interface and decouple from the authentication features. As noted in the original issue, this could potentially be accomplished within the existing security component. However, if we continue with this proposal, our biggest challenge will be handling multiple classes with incompatible interfaces within the same namespace. Creating a separate component will simplify development (I guess the console/terminal components face a similar challenge).The design I’m proposing is not particularly groundbreaking.
There is a single
AccessControlManagerInterface
with one method:AccessRequest
contains:requester
i.e. the user who is requesting an authorization. A TokenInterface is expected. This can be the current logged in user, a user for another user, a console command or anything relevant as per your application needs,mixed
type) for which you want to gather votes,mixed
type),The decision is determined by the specified strategy depending on the voter outcomes.
RBAC or Expression voters and
affirmative
,consensus
, orunanimous
strategies in this initial commit. The returnedAccessDecision
object containsstring
).Also, for this first commit, I created three attributes:
AccessPolicy
– similar toisGranted
:The difference is that you can override the default strategy or allow access if all voters abstain:
All
andAtLeastOneOf
These attributes enable fine-grained decisions on multiple AccessPolicy attributes, intended for more complex scenarios:
I’m looking forward to your feedback and suggestions!