Before I dive into reinventing the wheel, I'd first like to check if ZF2 supports, either out-of-the-box or with a 3rd party library, this particular use case where admins log in as
other user, or assume
their identity.
If not, as I'm not familiar with ZF2 internal design, how would I go into implementing this, with the only constraint being that the system is already built, so I can't change components (controllers, auth services, etc) into supporting it.
My first thought would be to make a mechanism to switch the logged user information stored in the session storage, with the one whose identity I want to assume. Then, write to the session, under a different namespace, the original user information (admin) so that it can be reverted.
Going by this approach, I am expecting components like Zend\Authentication\AuthenticationService
return the user whose identity I'm assuming. So, in every call I make to $this->identity()->getId()
(identity being a controller plugin for AuthenticationService, that returns the User
) in other controllers, the business logic will work normally.
Having said this, the questions would be:
I think you would need to create your own AuthenticationAdaptor.
class AdminUserLoginAsUser implements \Zend\Authentication\Adapter\AdapterInterface
{
/**
* @var User
*/
private $userToLoginAs;
/**
* @var AdminUser
*/
private $adminUser;
public function __construct(User $userToLoginAs, AdminUser $adminUser)
{
$this->userToLoginAs = $userToLoginAs;
$this->adminUser = $adminUser;
}
/**
* Performs an authentication attempt
*
* @return \Zend\Authentication\Result
* @throws \Zend\Authentication\Adapter\Exception\ExceptionInterface If authentication cannot be performed
*/
public function authenticate()
{
return new \Zend\Authentication\Result(
Result::SUCCESS, $this->user, [
'You have assumed control of user.',
]
);
}
}
The above class will allow you to login as another user when used with Zend's AuthenticationService class.
You will need some way of using Zend's AuthenticationService class and I would recommend using an AuthManager that wraps around the AuthenticationService.
/**
* The AuthManager service is responsible for user's login/logout and simple access
* filtering. The access filtering feature checks whether the current visitor
* is allowed to see the given page or not.
*/
class AuthManager
{
/**
* Authentication service.
* @var \Zend\Authentication\AuthenticationService
*/
private $authService;
/**
* Session manager.
* @var Zend\Session\SessionManager
*/
private $sessionManager;
/**
* Contents of the 'access_filter' config key.
* @var array
*/
private $config;
/**
* Constructs the service.
*/
public function __construct($authService, $sessionManager, $config)
{
$this->authService = $authService;
$this->sessionManager = $sessionManager;
$this->config = $config;
}
/**
* Performs a login attempt. If $rememberMe argument is true, it forces the session
* to last for one month (otherwise the session expires on one hour).
*/
public function login($email, $password, $rememberMe)
{
// Check if user has already logged in. If so, do not allow to log in
// twice.
if ($this->authService->getIdentity()!=null) {
throw new \Exception('Already logged in');
}
// Authenticate with login/password.
$authAdapter = $this->authService->getAdapter();
$authAdapter->setEmail($email);
$authAdapter->setPassword($password);
$result = $this->authService->authenticate();
// If user wants to "remember him", we will make session to expire in
// one month. By default session expires in 1 hour (as specified in our
// config/global.php file).
if ($result->getCode()==Result::SUCCESS && $rememberMe) {
// Session cookie will expire in 1 month (30 days).
$this->sessionManager->rememberMe(60*60*24*30);
}
return $result;
}
public function loginAsUser($user)
{
// Check if user has already logged in. If so, do not allow to log in
// twice.
if ($this->authService->getIdentity() !== null) {
throw new \Exception('Not logged in.');
}
// First need to logout of current user
$this->authService->clearIdentity();
$authAdapter = $this->authService->setAdapter(new AdminUserLoginAsUser($user, $this->authService->getIdentity()));
return $this->authService->authenticate();
}
/**
* Performs user logout.
*/
public function logout()
{
// Allow to log out only when user is logged in.
if ($this->authService->getIdentity()==null) {
throw new \Exception('The user is not logged in');
}
// Remove identity from session.
$this->authService->clearIdentity();
}
}
To see how to plug it all together I would recommend looking at the following resources:
The resources are for zf3 but I think the authenticating of users and managing authentication is very similar to zf2.