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