@@ -195,25 +195,81 @@ also adjust the query parameter name via the ``parameter`` setting:
195195 Limiting User Switching
196196-----------------------
197197
198- If you need more control over user switching, but don't require the complexity
199- of a full ACL implementation, you can use a security voter. For example, you
200- may want to allow employees to be able to impersonate a user with the
201- ``ROLE_CUSTOMER `` role without giving them the ability to impersonate a more
202- elevated user such as an administrator.
198+ If you need more control over user switching, you can use a security voter. First,
199+ configure ``switch_user `` to check for some new, custom attribute. This can be
200+ anything, but *cannot * start with ``ROLE_ `` (to enforce that only your voter will)
201+ be called:
203202
204- Create the voter class::
203+ .. configuration-block ::
204+
205+ .. code-block :: yaml
206+
207+ # config/packages/security.yaml
208+ security :
209+ # ...
210+
211+ firewalls :
212+ main :
213+ # ...
214+ switch_user : { role: CAN_SWITCH_USER }
215+
216+ .. code-block :: xml
217+
218+ <!-- config/packages/security.xml -->
219+ <?xml version =" 1.0" encoding =" UTF-8" ?>
220+ <srv : container xmlns =" http://symfony.com/schema/dic/security"
221+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
222+ xmlns : srv =" http://symfony.com/schema/dic/services"
223+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
224+ https://symfony.com/schema/dic/services/services-1.0.xsd" >
225+ <config >
226+ <!-- ... -->
227+
228+ <firewall name =" main" >
229+ <!-- ... -->
230+ <switch-user role =" CAN_SWITCH_USER" />
231+ </firewall >
232+ </config >
233+ </srv : container >
234+
235+ .. code-block :: php
236+
237+ // config/packages/security.php
238+ $container->loadFromExtension('security', [
239+ // ...
240+
241+ 'firewalls' => [
242+ 'main'=> [
243+ // ...
244+ 'switch_user' => [
245+ 'role' => 'CAN_SWITCH_USER',
246+ ],
247+ ],
248+ ],
249+ ]);
250+
251+ Then, create a voter class that responds to this role and includes whatever custom
252+ logic you want::
205253
206254 namespace App\Security\Voter;
207255
208256 use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
209257 use Symfony\Component\Security\Core\Authorization\Voter\Voter;
258+ use Symfony\Component\Security\Core\Security;
210259 use Symfony\Component\Security\Core\User\UserInterface;
211260
212261 class SwitchToCustomerVoter extends Voter
213262 {
263+ private $security;
264+
265+ public function __construct(Security $security)
266+ {
267+ $this->security = $security;
268+ }
269+
214270 protected function supports($attribute, $subject)
215271 {
216- return in_array($attribute, ['ROLE_ALLOWED_TO_SWITCH '])
272+ return in_array($attribute, ['CAN_SWITCH_USER '])
217273 && $subject instanceof UserInterface;
218274 }
219275
@@ -225,27 +281,29 @@ Create the voter class::
225281 return false;
226282 }
227283
228- if (in_array('ROLE_CUSTOMER', $subject->getRoles())
229- && in_array('ROLE_SWITCH_TO_CUSTOMER', $token->getRoleNames(), true)) {
284+ // you can still check for ROLE_ALLOWED_TO_SWITCH
285+ if ($this->security->isGranted('ROLE_ALLOWED_TO_SWITCH')) {
286+ return true;
287+ }
288+
289+ // check for any roles you want
290+ if ($this->security->isGranted('ROLE_TECH_SUPPORT')) {
230291 return true;
231292 }
232293
294+ /*
295+ * or use some custom data from your User object
296+ if ($user->isAllowedToSwitch()) {
297+ return true;
298+ }
299+ */
300+
233301 return false;
234302 }
235303 }
236304
237- .. versionadded :: 4.3
238-
239- The ``getRoleNames() `` method was introduced in Symfony 4.3.
240-
241- To enable the new voter in the app, register it as a service and
242- :doc: `tag it </service_container/tags >` with the ``security.voter ``
243- tag. If you're using the
244- :ref: `default services.yaml configuration <service-container-services-load-example >`,
245- this is already done for you, thanks to :ref: `autoconfiguration <services-autoconfigure >`.
246-
247- Now a user who has the ``ROLE_SWITCH_TO_CUSTOMER `` role can switch to a user who
248- has the ``ROLE_CUSTOMER `` role, but not other users.
305+ That's it! When switching users, your voter now has full control over whether or
306+ not this is allowed. If your voter isn't called, see :ref: `declaring-the-voter-as-a-service `.
249307
250308Events
251309------
0 commit comments