@@ -191,25 +191,81 @@ also adjust the query parameter name via the ``parameter`` setting:
191
191
Limiting User Switching
192
192
-----------------------
193
193
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:
199
198
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::
201
249
202
250
namespace App\Security\Voter;
203
251
204
252
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
205
253
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
254
+ use Symfony\Component\Security\Core\Security;
206
255
use Symfony\Component\Security\Core\User\UserInterface;
207
256
208
257
class SwitchToCustomerVoter extends Voter
209
258
{
259
+ private $security;
260
+
261
+ public function __construct(Security $security)
262
+ {
263
+ $this->security = $security;
264
+ }
265
+
210
266
protected function supports($attribute, $subject)
211
267
{
212
- return in_array($attribute, ['ROLE_ALLOWED_TO_SWITCH '])
268
+ return in_array($attribute, ['CAN_SWITCH_USER '])
213
269
&& $subject instanceof UserInterface;
214
270
}
215
271
@@ -221,23 +277,29 @@ Create the voter class::
221
277
return false;
222
278
}
223
279
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' )) {
226
282
return true;
227
283
}
228
284
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
+
229
297
return false;
230
298
}
231
299
}
232
300
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 `.
241
303
242
304
Events
243
305
------
0 commit comments