diff --git a/components/security/authorization.rst b/components/security/authorization.rst index ffc4edc278a..3effc3d0794 100644 --- a/components/security/authorization.rst +++ b/components/security/authorization.rst @@ -37,26 +37,8 @@ Access Decision Manager Since deciding whether or not a user is authorized to perform a certain action can be a complicated process, the standard :class:`Symfony\\Component\\Security\\Core\\Authorization\\AccessDecisionManager` itself depends on multiple voters, and makes a final verdict based on all -the votes (either positive, negative or neutral) it has received. It -recognizes several strategies: - -``affirmative`` (default) - grant access as soon as there is one voter granting access; - -``consensus`` - grant access if there are more voters granting access than there are denying; - -``unanimous`` - only grant access if none of the voters has denied access. If all voters - abstained from voting, the decision is based on the ``allow_if_all_abstain`` - config option (which defaults to ``false``). - -``priority`` - grants or denies access by the first voter that does not abstain; - - .. versionadded:: 5.1 - - The ``priority`` version strategy was introduced in Symfony 5.1. +the votes (either positive, negative or neutral) it has received and the +given strategy. Usage of the available options in detail:: @@ -65,27 +47,69 @@ Usage of the available options in detail:: // instances of Symfony\Component\Security\Core\Authorization\Voter\VoterInterface $voters = [...]; - // one of "affirmative", "consensus", "unanimous", "priority" + // instance of Symfony\Component\Security\Core\Authorization\Strategy\AccessDecisionStrategyInterface $strategy = ...; - // whether or not to grant access when all voters abstain - $allowIfAllAbstainDecisions = ...; - - // whether or not to grant access when there is no majority (applies only to the "consensus" strategy) - $allowIfEqualGrantedDeniedDecisions = ...; - - $accessDecisionManager = new AccessDecisionManager( - $voters, - $strategy, - $allowIfAllAbstainDecisions, - $allowIfEqualGrantedDeniedDecisions - ); + $accessDecisionManager = new AccessDecisionManager($voters, $strategy); .. seealso:: You can change the default strategy in the :ref:`configuration `. +Strategies +---------- + +.. versionadded:: 5.4 + + The strategy classes were introduced in Symfony 5.4. In earlier versions, the strategy was passed as a string. + +The following strategies are bundled with the component: + +``AffirmativeStrategy`` (default) + grant access as soon as there is one voter granting access; + +``ConsensusStrategy`` + grant access if there are more voters granting access than there are denying; + if there is a draw between votes, the decision is made based on the + ``$allowIfEqualGrantedDeniedDecisions`` constructor parameter which defaults to ``true``. + +``UnanimousStrategy`` + only grant access if none of the voters has denied access. + +``PriorityStrategy`` + grants or denies access by the first voter that does not abstain; + + .. versionadded:: 5.1 + + The "priority" version strategy was introduced in Symfony 5.1. + +If all voters abstained from voting, the decision is based on the ``$allowIfAllAbstainDecisions`` +constructor parameter which is supported by all of the built-in strategies and defaults to ``false``. + +If none of the built-in strategies seem to fit, a custom strategy may be provided. The strategy will +receive a stream of votes and may return as soon as it has seen enough votes to come to a conclusion. + +:: + + /** + * Always picks the third voter. + */ + class ThirdVoterStrategy implements AccessDecisionStrategyInterface + { + public function decide(\Traversable $results): bool + { + $votes = 0; + foreach ($results as $result) { + if (++$votes === 3) { + return $result === VoterInterface::ACCESS_GRANTED; + } + } + + return false; + } + } + Voters ------ diff --git a/security/voters.rst b/security/voters.rst index d860886f175..6b8d674adab 100644 --- a/security/voters.rst +++ b/security/voters.rst @@ -345,7 +345,58 @@ security configuration: Custom Access Decision Strategy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If none of the built-in strategies fits your use case, define the ``service`` +.. versionadded:: 5.4 + + The ``strategy_service`` option was introduced in Symfony 5.4. + +If none of the built-in strategies fits your use case, define the ``strategy_service`` +option to use a custom service (your service must implement the +:class:`Symfony\\Component\\Security\\Core\Authorization\\Strategy\\AccessDecisionStrategyInterface`): + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + access_decision_manager: + strategy_service: App\Security\MyCustomAccessDecisionStrategy + # ... + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use App\Security\MyCustomAccessDecisionStrategy; + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->accessDecisionManager() + ->strategyService(MyCustomAccessDecisionStrategy::class) + // ... + ; + }; + +Custom Access Decision Manager +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you need to provide an entirely custom access decision manager, define the ``service`` option to use a custom service as the Access Decision Manager (your service must implement the :class:`Symfony\\Component\\Security\\Core\\Authorization\\AccessDecisionManagerInterface`):