User switch with custom restrictions in Symfony

本文介绍如何在Symfony中实现特定角色用户的账号切换功能。通过利用SwitchUserListener并自定义订阅SecurityEvents::SWITCH_USER事件,确保只有指定角色的用户才能切换到与其有关联的其他用户。

Recently we found ourselves in a situation where we needed to implement user switching/impersonating functionality. Which means a user can "log in" as another user. 

This needed to be done by other (non-admin) users that have certain relations. A user can be linked to multiple other users under the relation managedUsers, which is a many-to-many relation. Users that are allowed to switch to a managed user have a specific role and can only switch to related users.

The Symfony security component supports this functionality, but only based on a certain role. Users with the role "ROLE_ALLOWED_TO_SWITCH" are allowed to switch users. This is great for admins for example, if the users that are granted this role are allowed to impersonate any user. This is definitely not the case in our situation. 

So, how did we do this?

First of all, we made sure the users that are allowed to switch were granted the role "ROLE_ALLOWED_TO_SWITCH". Next, we quickly stumbled uponSymfony\Component\Security\Http\Firewall\SwitchUserListener, this is where the switching actually happens. Certain checks are made and a new token is built.

Methods attemptSwitchUser and attemptExitUser are the ones we need to try and hook into. We could override the SwitchUserListener, but if you look closely, an event is being dispatched at the end of each method containing the user we're switching to.

So we create a listener, or in this case, a subscriber:

 

We subscribe to the SecurityEvents::SWITCH_USER event which is thrown at the end of both methods.

Now we realise that we only have access to the target user. So we don't know anything about the context. We need the original user and the target user to be able to check the things we want. Luckily this is easily accomplished by injecting the token storage into our subscriber. And since we only need to throw an AccessDeniedException to stop the switching, this is all we need.

 

Add the subscriber to the services.yml:

 

Next we need to implement our logic, so we added the following methods to the subscriber:

 

Here we want to check if our user that is doing the impersonating is actually managing the user we're trying to impersonate. We check this for both directions, so even when trying to exit the impersonation. This way we're sure there will be no situation where the user gets access to the wrong account.

Let's put it all together:

 

The actual implementation is a bit different, these code snippets are purely for demonstration purposes. Feel free to post improvements or other/better ways to tackle this issue!

转载于:https://my.oschina.net/u/144160/blog/739003

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值