zend-framework2zend-auth

zend-authentication - setting identity to custom object with rbac roles loaded


In a ZF2 project i am using the AuthenticationService to validate a users log in credentials. This is working fine, except it only stores in the session a string containing the users name.

What i would like would be for subsequent calls to AuthenticationService::getIdentity to return a custom Identity object, that is populated with the users database id, roles and permissions (popualted from an RBAC service), so that the object in the session is a bit more useful.

I am able to create this object, but am unsure of the best way to keep it in the session; ideally i would like to override the entry with the key Zend_Auth, but this does not seem to be working.

My code so far:

<?php
namespace Authentication\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Authentication\AuthenticationService;
use Authentication\Form\Login\LoginForm;
use Zend\Form\Form;
use Authentication\Model\Identity\AuthenticatedIdentity;

class AuthenticationController extends AbstractActionController
{
    /**
    *
    * @var AuthenticationService
    */
    protected $authenticationService;

    /**
    *
    * @var LoginForm
    */
    protected $loginForm;

    /**
    *
    * @param AuthenticationService $authenticationService
    * @param LoginForm $loginForm
    */
    public function __construct(AuthenticationService $authenticationService, LoginForm $loginForm){
        $this->authenticationService = $authenticationService;
        $this->loginForm = $loginForm;
    }

    public function indexAction(){
        $form = $this->loginForm;
        $viewModel = new ViewModel();

        $viewModel->setVariables([
            'loginForm' => $form
        ]);

        if($this->getRequest()->isPost() === false){
            return $viewModel;
        }

        $form->setData($this->getRequest()->getPost());

        if($form->isValid() === false){
            return $viewModel;
        }

        $data = $form->getData();

        $authenticationAdapter = $this->authenticationService->getAdapter();
        $authenticationAdapter->setIdentity($data['credentials']['username'])
            ->setCredential($data['credentials']['password']);
        $authenticationResult = $this->authenticationService->authenticate($authenticationAdapter);

        if($authenticationResult->isValid() === false){
            $viewModel->setVariable('validCredentials', false);
            return $viewModel;
        }

        /**
         * Create a user model and save it to the session.
         */
         $authenticationResultRow = $authenticationAdapter->getResultRowObject(null, ['password']);

        $permissions = $this->rbacService->getPermissionsForUser($authenticationResultRow->user_id);
        $roles = $this->rbacService->getRolesForUser($authenticationResultRow->user_id);

        $identity = new AuthenticatedIdentity(
            $authenticationResult->getIdentity(),
            'admin',
            $permissions,
            $roles
        );
        $identity->setUserId($authenticationResultRow->user_id);

        //how to store this Identity object in session so AuthenticationService will return it?

        return $this->redirect()->toRoute('dashboard');
    }
}

Solution

  • Check out https://github.com/zendframework/zend-authentication/blob/master/src/AuthenticationService.php#L75 and https://github.com/zendframework/zend-authentication/blob/master/src/Storage/StorageInterface.php

    You can write the AuthenticatedIdentity object directly to the storage like so:

    $this->authenticationService->getStorage()->write($identity);
    

    However, I would advice against doing so because:

    1. If the user's permissions/roles change during the session he/she would have to log out and back in to see any changes which is not very user-friendly.
    2. Your AuthenticatedIdentity object and all objects it contains need to be serializable, which can become problematic to maintain.

    I would (and do) fetch the user object and/or roles when needed, either from DB or some form of cache but don't store it in the session.