@@ -195,25 +195,81 @@ also adjust the query parameter name via the ``parameter`` setting:
195
195
Limiting User Switching
196
196
-----------------------
197
197
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:
203
202
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::
205
253
206
254
namespace App\Security\Voter;
207
255
208
256
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
209
257
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
258
+ use Symfony\Component\Security\Core\Security;
210
259
use Symfony\Component\Security\Core\User\UserInterface;
211
260
212
261
class SwitchToCustomerVoter extends Voter
213
262
{
263
+ private $security;
264
+
265
+ public function __construct(Security $security)
266
+ {
267
+ $this->security = $security;
268
+ }
269
+
214
270
protected function supports($attribute, $subject)
215
271
{
216
- return in_array($attribute, ['ROLE_ALLOWED_TO_SWITCH '])
272
+ return in_array($attribute, ['CAN_SWITCH_USER '])
217
273
&& $subject instanceof UserInterface;
218
274
}
219
275
@@ -225,27 +281,29 @@ Create the voter class::
225
281
return false;
226
282
}
227
283
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')) {
230
291
return true;
231
292
}
232
293
294
+ /*
295
+ * or use some custom data from your User object
296
+ if ($user->isAllowedToSwitch()) {
297
+ return true;
298
+ }
299
+ */
300
+
233
301
return false;
234
302
}
235
303
}
236
304
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 `.
249
307
250
308
Events
251
309
------
0 commit comments