@@ -191,25 +191,81 @@ also adjust the query parameter name via the ``parameter`` setting:
191191 Limiting User Switching
192192-----------------------
193193
194- If you need more control over user switching, but don't require the complexity
195- of a full ACL implementation, you can use a security voter. For example, you
196- may want to allow employees to be able to impersonate a user with the
197- ``ROLE_CUSTOMER `` role without giving them the ability to impersonate a more
198- elevated user such as an administrator.
194+ If you need more control over user switching, you can use a security voter. First,
195+ configure ``switch_user `` to check for some new, custom attribute. This can be
196+ anything, but *cannot * start with ``ROLE_ `` (to enforce that only your voter will)
197+ be called:
199198
200- Create the voter class::
199+ .. configuration-block ::
200+
201+ .. code-block :: yaml
202+
203+ # config/packages/security.yaml
204+ security :
205+ # ...
206+
207+ firewalls :
208+ main :
209+ # ...
210+ switch_user : { role: CAN_SWITCH_USER }
211+
212+ .. code-block :: xml
213+
214+ <!-- config/packages/security.xml -->
215+ <?xml version =" 1.0" encoding =" UTF-8" ?>
216+ <srv : container xmlns =" http://symfony.com/schema/dic/security"
217+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
218+ xmlns : srv =" http://symfony.com/schema/dic/services"
219+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
220+ https://symfony.com/schema/dic/services/services-1.0.xsd" >
221+ <config >
222+ <!-- ... -->
223+
224+ <firewall name =" main" >
225+ <!-- ... -->
226+ <switch-user role =" CAN_SWITCH_USER" />
227+ </firewall >
228+ </config >
229+ </srv : container >
230+
231+ .. code-block :: php
232+
233+ // config/packages/security.php
234+ $container->loadFromExtension('security', [
235+ // ...
236+
237+ 'firewalls' => [
238+ 'main'=> [
239+ // ...
240+ 'switch_user' => [
241+ 'role' => 'CAN_SWITCH_USER',
242+ ],
243+ ],
244+ ],
245+ ]);
246+
247+ Then, create a voter class that responds to this role and includes whatever custom
248+ logic you want::
201249
202250 namespace App\Security\Voter;
203251
204252 use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
205253 use Symfony\Component\Security\Core\Authorization\Voter\Voter;
254+ use Symfony\Component\Security\Core\Security;
206255 use Symfony\Component\Security\Core\User\UserInterface;
207256
208257 class SwitchToCustomerVoter extends Voter
209258 {
259+ private $security;
260+
261+ public function __construct(Security $security)
262+ {
263+ $this->security = $security;
264+ }
265+
210266 protected function supports($attribute, $subject)
211267 {
212- return in_array($attribute, ['ROLE_ALLOWED_TO_SWITCH '])
268+ return in_array($attribute, ['CAN_SWITCH_USER '])
213269 && $subject instanceof UserInterface;
214270 }
215271
@@ -221,23 +277,29 @@ Create the voter class::
221277 return false;
222278 }
223279
224- if (in_array('ROLE_CUSTOMER', $subject->getRoles())
225- && in_array('ROLE_SWITCH_TO_CUSTOMER', $token->getRoleNames(), true )) {
280+ // you can still check for ROLE_ALLOWED_TO_SWITCH
281+ if ($this->security->isGranted('ROLE_ALLOWED_TO_SWITCH' )) {
226282 return true;
227283 }
228284
285+ // check for any roles you want
286+ if ($this->security->isGranted('ROLE_TECH_SUPPORT')) {
287+ return true;
288+ }
289+
290+ /*
291+ * or use some custom data from your User object
292+ if ($user->isAllowedToSwitch()) {
293+ return true;
294+ }
295+ */
296+
229297 return false;
230298 }
231299 }
232300
233- To enable the new voter in the app, register it as a service and
234- :doc: `tag it </service_container/tags >` with the ``security.voter ``
235- tag. If you're using the
236- :ref: `default services.yaml configuration <service-container-services-load-example >`,
237- this is already done for you, thanks to :ref: `autoconfiguration <services-autoconfigure >`.
238-
239- Now a user who has the ``ROLE_SWITCH_TO_CUSTOMER `` role can switch to a user who
240- has the ``ROLE_CUSTOMER `` role, but not other users.
301+ That's it! When switching users, your voter now has full control over whether or
302+ not this is allowed. If your voter isn't called, see :ref: `declaring-the-voter-as-a-service `.
241303
242304Events
243305------
0 commit comments