|
| 1 | +.. index:: |
| 2 | + single: Security, Authorization |
| 3 | + |
| 4 | +Authorization |
| 5 | +============= |
| 6 | + |
| 7 | +When any of the authentication providers (see :ref:`authentication_providers`) |
| 8 | +has verified the still unauthenticated token, an authenticated token will |
| 9 | +be returned. The authentication listener should set this token directly |
| 10 | +in the :class:`Symfony\\Component\\Security\\Core\\SecurityContext` using its |
| 11 | +``setToken()`` method. |
| 12 | + |
| 13 | +From then on, the user is authenticated, i.e. means identified. |
| 14 | +Now, other parts of the application can use the token to decide whether |
| 15 | +or not the user may request a certain URI, or modify a certain object. |
| 16 | +This decision will be made by an instance of :class:`Symfony\\Component\\Security\\Core\\Authorization\\AccessDecisionManagerInterface`. |
| 17 | + |
| 18 | +An authorization decision will always be based on a few things: |
| 19 | + |
| 20 | +The current token |
| 21 | + The token`s ``getRoles()`` method will be used to retrieve the roles |
| 22 | + of the current user (e.g. "ROLE_SUPER_ADMIN") |
| 23 | +A set of attributes |
| 24 | + Each attribute stands for a certain right the user should have, e.g. |
| 25 | + "ROLE_ADMIN" to make sure the user is an administrator. |
| 26 | +An object (optional) |
| 27 | + Any object on which to decide, e.g. the current :class:`Symfony\\Component\\HttpFoundation\\Request` |
| 28 | + object. |
| 29 | + |
| 30 | +Access decision manager |
| 31 | +----------------------- |
| 32 | + |
| 33 | +Since choosing whether or not a user is authorized to perform a certain |
| 34 | +action can be a complicated process, the standard :class:`Symfony\\Component\\Security\\Core\\Authorization\\AccessDecisionManager` |
| 35 | +itself depends on multiple voters, and makes a final verdict based on all |
| 36 | +the votes (either positive, negative or neutral) it has received. It |
| 37 | +recognizes several strategies: |
| 38 | + |
| 39 | +``affirmative`` (default) |
| 40 | + Grant access as soon as any voter returns an affirmative response |
| 41 | + |
| 42 | +``consensus`` |
| 43 | + Grant access if there are more voters granting access then there are denying |
| 44 | + |
| 45 | +``unanimous`` |
| 46 | + Only grant access if none of the voters has denied access |
| 47 | + |
| 48 | +:: |
| 49 | + |
| 50 | + use Symfony\Component\Security\Core\Authorization\AccessDecisionManager; |
| 51 | + |
| 52 | + // instances of Symfony\Component\Security\Core\Authorization\Voter\VoterInterface |
| 53 | + $voters = array(...); |
| 54 | + |
| 55 | + // one of "affirmative", "consensus", "unanimous" |
| 56 | + $strategy = ...; |
| 57 | + |
| 58 | + // whether or not to grant access when all voters abstain |
| 59 | + $allowIfAllAbstainDecisions = ...; |
| 60 | + |
| 61 | + // whether or not to grant access when there is no majority (applies only to the "consensus" strategy) |
| 62 | + $allowIfEqualGrantedDeniedDecisions = ...; |
| 63 | + |
| 64 | + $accessDecisionManager = new AccessDecisionManager($voters, $strategy, |
| 65 | + $allowIfAllAbstainDecisions, $allowIfEqualGrantedDeniedDecisions); |
| 66 | + |
| 67 | +Voters |
| 68 | +------ |
| 69 | + |
| 70 | +Voters are instances |
| 71 | +of :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface`, |
| 72 | +which means they have to implement a few methods which allows the decision |
| 73 | +manager to use them: |
| 74 | + |
| 75 | +``supportsAttribute($attribute)`` |
| 76 | + Will be used to check if the voter knows how to handle the given attribute. |
| 77 | +``supportsClass($class)`` |
| 78 | + Will be used to check if the voter is able to grant or deny access for |
| 79 | + an object of the given class. |
| 80 | +``vote(TokenInterface $token, $object, array $attributes)`` |
| 81 | + This method will do the actual voting and return a value equal to one |
| 82 | + of the class constants of :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface`, |
| 83 | + i.e. ``VoterInterface::ACCESS_GRANTED``, ``VoterInterface::ACCESS_DENIED`` |
| 84 | + or ``VoterInterface::ACCESS_ABSTAIN``. |
| 85 | + |
| 86 | +The security component contains some standard voters which cover many use |
| 87 | +cases: |
| 88 | + |
| 89 | +The :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\AuthenticatedVoter` |
| 90 | +voter supports the attributes "IS_AUTHENTICATED_FULLY", "IS_AUTHENTICATED_REMEMBERED", |
| 91 | +and "IS_AUTHENTICATED_ANONYMOUSLY" and grants access based on the current |
| 92 | +level of authentication, i.e. is the user fully authenticated, or only based |
| 93 | +on a "remember-me" cookie, or even authenticated anonymously? |
| 94 | + |
| 95 | +:: |
| 96 | + |
| 97 | + use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver; |
| 98 | + |
| 99 | + $anonymousClass = 'Symfony\Component\Security\Core\Authentication\Token\AnonymousToken'; |
| 100 | + $rememberMeClass = 'Symfony\Component\Security\Core\Authentication\Token\RememberMeToken'; |
| 101 | + |
| 102 | + $trustResolver = new AuthenticationTrustResolver($anonymousClass, $rememberMeClass); |
| 103 | + |
| 104 | + $authenticatedVoter = new AuthenticatedVoter($trustResolver); |
| 105 | + |
| 106 | + // instance of Symfony\Component\Security\Core\Authentication\Token\TokenInterface |
| 107 | + $token = ... |
| 108 | + |
| 109 | + // any object |
| 110 | + $object = ... |
| 111 | + |
| 112 | + $vote = $authenticatedVoter->vote($token, $object, array('IS_AUTHENTICATED_FULLY'); |
| 113 | + |
| 114 | +The :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\RoleVoter` |
| 115 | +supports attributes starting with "ROLE_" and grants access to the user |
| 116 | +when the required "ROLE_*" attributes can all be found in the array of |
| 117 | +roles returned by the token's ``getRoles()`` method. |
| 118 | + |
| 119 | +:: |
| 120 | + |
| 121 | + use Symfony\Component\Security\Core\Authorization\Voter\RoleVoter; |
| 122 | + |
| 123 | + $roleVoter = new RoleVoter('ROLE_'); |
| 124 | + |
| 125 | + $roleVoter->vote($token, $object, 'ROLE_ADMIN'); |
| 126 | + |
| 127 | +The :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\RoleHierarchyVoter` |
| 128 | +extends :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\RoleVoter` |
| 129 | +and provides some additional functionality: it knows how to handle a |
| 130 | +hierarchy of roles. For instance, a "ROLE_SUPER_ADMIN" role may have subroles |
| 131 | +"ROLE_ADMIN" and "ROLE_USER", so that when a certain object requires the |
| 132 | +user to have the "ROLE_ADMIN" role, it grants access to users who in fact |
| 133 | +have the "ROLE_ADMIN" role, but also to users having the "ROLE_SUPER_ADMIN" |
| 134 | +role. |
| 135 | + |
| 136 | +:: |
| 137 | + |
| 138 | + use Symfony\Component\Security\Core\Authorization\Voter\RoleHierarchyVoter; |
| 139 | + use Symfony\Component\Security\Core\Role\RoleHierarchy; |
| 140 | + |
| 141 | + $hierarchy = array( |
| 142 | + 'ROLE_SUPER_ADMIN' => array('ROLE_ADMIN', 'ROLE_USER'), |
| 143 | + ); |
| 144 | + |
| 145 | + $roleHierarchy = new RoleHierarchy($hierarchy); |
| 146 | + |
| 147 | + $roleHierarchyVoter = new RoleHierarchyVoter($roleHierarchy); |
| 148 | + |
| 149 | +.. note:: |
| 150 | + |
| 151 | + When you make your own voter, you may of course use its constructor |
| 152 | + to inject any dependencies it needs to come to a decision. |
| 153 | + |
| 154 | +Roles |
| 155 | +----- |
| 156 | + |
| 157 | +Roles are objects that give expression to a certain right the user has. |
| 158 | +The only requirement is that they implement :class:`Symfony\\Component\\Security\\Core\\Role\\RoleInterface`, |
| 159 | +which means they should also have a ``getRole()`` method that returns a |
| 160 | +string representation of the role itself. The default :class:`Symfony\\Component\\Security\\Core\\Role\\Role` |
| 161 | +simply returns its first constructor argument: |
| 162 | + |
| 163 | +:: |
| 164 | + |
| 165 | + use Symfony\Component\Security\Core\Role\Role; |
| 166 | + |
| 167 | + $role = new Role('ROLE_ADMIN'); |
| 168 | + |
| 169 | + // will echo 'ROLE_ADMIN' |
| 170 | + echo $role->getRole(); |
| 171 | + |
| 172 | +.. note:: |
| 173 | + |
| 174 | + Most authentication tokens extend from :class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\AbstractToken`, |
| 175 | + which means that the roles given to its constructor, will be |
| 176 | + automatically converted from strings to these simple ``Role`` objects. |
| 177 | + |
| 178 | +Using the decision manager |
| 179 | +-------------------------- |
| 180 | + |
| 181 | +The access listener |
| 182 | +~~~~~~~~~~~~~~~~~~~ |
| 183 | + |
| 184 | +Normally, the access decision manager will already be asked to decide whether |
| 185 | +or not the current user is entitled to make the current request. This is done |
| 186 | +by the :class:`Symfony\\Component\\Security\\Http\\Firewall\\AccessListener`, |
| 187 | +which is one of the firewall listeners (see :ref:`firewall_listeners`) that |
| 188 | +will be triggered for each request matching the firewall map (see :ref:`firewall`). |
| 189 | + |
| 190 | +It uses an access map (which should be an instance of :class:`Symfony\\Component\\Security\\Http\\AccessMapInterface`) |
| 191 | +which contains request matchers and a corresponding set of attributes that |
| 192 | +are required for the current user to get access to the application. |
| 193 | + |
| 194 | +:: |
| 195 | + |
| 196 | + use Symfony\Component\Security\Http\AccessMap; |
| 197 | + use Symfony\Component\HttpFoundation\RequestMatcher; |
| 198 | + use Symfony\Component\Security\Http\Firewall\AccessListener; |
| 199 | + |
| 200 | + $accessMap = new AccessMap(); |
| 201 | + $requestMatcher = new RequestMatcher('^/admin'); |
| 202 | + $accessMap->add($requestMatcher, array('ROLE_ADMIN')); |
| 203 | + |
| 204 | + $accessListener = new AccessListener($securityContext, $accessDecisionManager, |
| 205 | + $accessMap, $authenticationManager); |
| 206 | + |
| 207 | +Security context |
| 208 | +~~~~~~~~~~~~~~~~ |
| 209 | + |
| 210 | +The access decision manager is also available to other parts of the application |
| 211 | +by means of the ``isGranted($attribute)`` method of the :class:`Symfony\\Component\\Security\\Core\\SecurityContext`. |
| 212 | +A call to this method will directly delegate the question to the access |
| 213 | +decision manager. |
| 214 | + |
| 215 | +:: |
| 216 | + |
| 217 | + use Symfony\Component\Security\SecurityContext; |
| 218 | + use Symfony\Component\Security\Core\Exception\AccessDeniedException; |
| 219 | + |
| 220 | + $securityContext = new SecurityContext(); |
| 221 | + |
| 222 | + if (!$securityContext->isGranted('ROLE_ADMIN')) { |
| 223 | + throw new AccessDeniedException(); |
| 224 | + } |
0 commit comments