I cannot Implement Laminas Authentication Validator to check for Identity

I want to implement an Authentication Service check across other my application (Modules) by calling my Auth\Adapter. I have been able to authenticate users against a db table. My Validator seems not to work properly.
.
This is my Authentication Adapter which works ok in authentication of users

<?php
namespace Auth\Adapter;

use Laminas\Authentication\Adapter\AdapterInterface;
use Laminas\Authentication\Adapter\DbTable\CredentialTreatmentAdapter as AuthAdapter;
use Laminas\Authentication\AuthenticationService;
use Laminas\Authentication\Result;
use Laminas\Authentication\Validator\Authentication as AuthenticationValidator;

class Adapter implements AdapterInterface
{
    const SUCCESS = 1;
    const FAILURE = 0;
    const FAILURE_IDENTITY_NOT_FOUND = -1;
    const FAILURE_IDENTITY_AMBIGUOUS = -2;
    const FAILURE_CREDENTIAL_INVALID = -3;
    const FAILURE_UNCATEGORIZED = -4;

    /**
     * Sets username and password for authentication
     *
     * @return void
     */
    public function __construct($username, $password)
    {
        $this->username = $username;
        $this->password = $password;
    }

    /**
     * Performs an authentication attempt
     *
     * @return \Laminas\Authentication\Result
     * @throws \Laminas\Authentication\Adapter\Exception\ExceptionInterface
     *     If authentication cannot be performed
     */
    public function authenticate()
    {
        // Configure the instance with setter methods:
        $authAdapter = $this->getAdapter();

        $authAdapter
            ->setTableName('kv_users_tenants')
            ->setIdentityColumn('email')
            ->setCredentialColumn('pass');

        // Set the input credential values (e.g., from a login form):
        $authAdapter
            ->setIdentity($this->username)
            ->setCredential($this->password);

        // Perform the authentication query, saving the result
        $auth = new AuthenticationService;
        $result = $auth->authenticate($authAdapter);
        //Store Validated responses in a an array
        $resp = [];
        switch ($result->getCode()) {

            case Result::FAILURE_IDENTITY_NOT_FOUND:
                /** do stuff for nonexistent identity **/
                $resp['status'] = 'error';
                $resp['msg'] = '<div class="alert alert-danger"><span class="fas fa-exclamation-circle"></span> That User does not exist</div>';
                break;
            case Result::FAILURE_CREDENTIAL_INVALID:
                /** do stuff for invalid credential **/
                $resp['status'] = 'error';
                $resp['msg'] = '<div class="alert alert-danger"><span class="fas fa-exclamation-circle"></span>  Incorrect Username or Password</div>';
                break;
            case Result::SUCCESS:
                //$resp = "successful Login Redirecxt Me";
                //$auth->getStorage()->write(['email' => $this->email]);
                /** do stuff for successful authentication **/
                //$this->authService->getStorage()->write(['work_email' => 'work@gmail.com']);
                $resp['status'] = 'success';
                $resp['route'] = 'tenant-dashboard';
                break;
        }
        return $resp;
    }

    public function ValidateAuth()
    {

        $service   = new AuthenticationService();
        $adapter   = $this->getAdapter();
        $adapter
            ->setTableName('kv_users_tenants')
            ->setIdentityColumn('email')
            ->setCredentialColumn('pass');

        $validator = new AuthenticationValidator([
            'service' => $service,
            'adapter' => $adapter,
        ]);
        return $validator->isValid();
    }

    public function getAdapter(){
        //Grab DB Adapter
        $adapter = new \Laminas\Db\Adapter\Adapter([
                    'driver'   => 'Mysqli',
                    'database' => 'kv_rent',
                    'username' => 'root',
                    'password' => 'chapati',
                ]);
       
        // Configure the instance with setter methods:
        $authAdapter = new AuthAdapter($adapter);
        return $authAdapter;
    }
}

In my Auth Controller
My login Action -->

public function loginAction()
{
    $response = "";
    if ($_POST) {
        //Collect and sanitize Login details
        $this->email = $_POST['email'];
        $this->pass = $_POST['password']; 

        //Initialize the Auth Adapter implements \Auth\Adapter\Adapter
        $resp = new Adapter($this->email, $this->pass);

        //Get the Authentication 
        $rsp = $resp->authenticate();

        //Display the response to View
        if($rsp['status'] !== 'success'){
            $response = $rsp['msg'];
        }else{
            //Redirect to Dashboard
            $this->redirect()->toRoute($rsp['route']);
        }

    }
    $view = new ViewModel(['resp_msg' => $response]); 
    return $view;  
}

My Validator


public function validateauthAction()
{
    $auth = new Adapter();
    $resp = $auth->ValidateAuth();
    //output response        
    var($resp)
    $view = new ViewModel();       
    return $view;
}

Please have a look at this example code which shows the usage of AuthenticationService with database adapter and the related helpers in a controller and view script:

1 Like

Hi Thanks for the answer, its helpful. I have done it before on ZF3 before migrating to Laminas. However on Laminas am not able to create multiple authentication services for different clearances (Tenant and Admin). I always get could not resolve to Factory whenever am authenticating an Admin for example. I would as well want an insight on how to properly implement the multiple storage eg. Session

From your code below, i would like to create an extra AuthenticationService say \Laminas\Authentication\AdminauthServiceInterface , but in my implementation i get an error Factory could not resolve to a factory.

'service_manager' => [
    'factories'  => [
        Zend\Authentication\AuthenticationServiceInterface::class => MyModule\AuthenticationServiceFactory::class,
    ],
],

Is the authentication process different for your user groups or why do you want to create another authentication service?

I actually Have 3 user Groups say,

  • Client
  • Admin
  • Staff

Each of these groups should have an Authentication Service callable from any other module in my application. Just to ensure i give each group relevant data in the app and ofcourse it should be Factory driven DI.
My challenge is

  • Creating multiple Authentication Services
  • Creating a custom storage interface and initiate Authentication Check from that specific Authentication Service.

This solution Problem in using the Identity Helper however does not explain further on implementing the identity Plugin which i believer would make the authentication validation easier.