How to do identity impersonation with Yii2

Yii2 provides a user application component that is responsible for user login, logout and other functions related to managing user authentication status.

Srdjan Drakul
Fullstack Developer

To begin this process, a basic user component configuration needs to be added inside components with its identityClass configured such as follows:

return [
	'components' => [
    	'user' => [
        	'identityClass' => common\models\User',
    	]
	]
];

Let's say you are logged into an application as an administrator but your goal is to impersonate another user. This can be really useful when you want to experience how an application looks and feels when viewed by another user.

For easier handling with the user component, we will override the default application user class and place some useful methods inside. Let's name it WebUser in order to avoid confusion between Active Record user and Application user.

namespace common\components;
 
use Yii;
use yii\web\User;
 
class WebUser extends User
{
	const IDENTITY_ID_KEY = 'mainIdentityId';
	const ADMIN_PERMISSION = 'admin';
 
	public function getIsImpersonated()
	{
    	return !is_null(Yii::$app->session->get(self::IDENTITY_ID_KEY));
	}
 
	public function setMainIdentityId($userId)
	{
  	  Yii::$app->sesion->set(self::IDENTITY_ID_KEY, $userId);
	}
 
	public function getMainIdentityId()
	{
    	$mainIdentityId = Yii::$app->session->get(self::IDENTITY_ID_KEY);
    	return !empty($mainIdentityId) ? $mainIdentityId : $this->getId();
	}
 
	public function getIsAdmin()
	{
    	return !$this->getIsGuest() && $this->can(self::ADMIN_PERMISSION);
	}
}

User components needs to be updated with this configuration:

return [
	'components' => [
    	'user' => [
          	'class' => 'common\components\WebUser'     	
         	'identityClass' => common\models\User',
    	]
	]
];

In order to get this done, we will have to create two separate actions inside our UserController. The first action is called actionImpersonate and it will be responsible for switching to another identity. The second one is actionStopImpersonating and it is responsible for returning back to our main identity. Since these actions are dealing with sensitive information and credentials, it is crucial to set AccessControl behavior and be certain that nobody except the admin will be able to switch to another identity.

use common\components\WebUser;
use common\models\User;
use yii\filters\AccessControl;
use yii\web\Controller;
 
class UserController extends Controller
{
	public function behaviors()
	{
    	return [
        	'access' => [
            	'class' => AccessControl::class,
            	'only' => ['impersonate', 'stop-impersonating'],
            	'rules' => [
             	   [
  	                  'actions' => ['impersonate', 'stop-impersonating'],
                    	'allow' => true,
                    	'roles' => ['@'],
                    	'matchCallback' => function () {
                        	return Yii::$app->getUser()->getIsAdmin();
                    	}
                	],
            	],
        	],
    	];
	}
 
 
	public function actionImpersonate($id)
	{
    	/** @var WebUser $webUser */
    	$webUser = Yii::$app->getUser();
 
        $mainIdentityId = $webUser->getMainIdentityId();
 
    	if ($mainIdentityId != $id) {
        	/** @var User $user */
        	$user = User::findOne($id);
 
        	$webUser->login($user, $duration = 0);
        	$webUser->setMainIdentityId($mainIdentityId);
    	}
 
    	return $this->redirect(['/land/user/to/route']);
	}
 
	public function actionStopImpersonating()
	{
    	/** @var WebUser $webUser */
    	$webUser = Yii::$app->getUser();
 
    	$mainIdentityId = $webUser->getMainIdentityId();
 
    	if (!empty($mainIdentityId)) {
        	/** @var User $user */
        	$user = User::findOne($mainIdentityId);
 
        	$webUser->login($user, $duration = 0);
        	$webUser->setMainIdentityId(null);
    	}
 
    	return $this->redirect(['/land/user/to/route']);
	}
}

When impersonation is done successfully, we can expect to see different data or a different presentation. All the data will be scoped for that user (if data scoping exists) along with permissions that that specific user has. Usually, impersonation is useful when an administrator of the system needs to check a regular user’s panel, whether for support, debugging, or simply in order to make sure the application is used correctly.