I'm trying to adapt my ZF2 User
module to ZF3 MVC. It has an authentication service manager that is called in the onBootsrap
function inside the Module
class for every request (i.e. page loading) to check if the user is authenticated.
As serviceLocator
and ServiceAware
are not available anymore I'm trying to create an AuthenticationServiceFactory
but I do not succeed yet. Would you have any ideas on what I'm doing wrong and how I could do it with ZF3 ?
Here is a simplified version of my module/User/config.module.config.php
file
namespace User;
use ...
return [
'router' => [...],
'controllers' => [...],
'service_manager' => [
'factories' => [
Service\AuthenticationServiceFactory::class => InvokableFactory::class,
],
],
];
Here is my module/User/src/Service/AuthenticationServiceFactory.php
file
namespace User\Service;
use Interop\Container\ContainerInterface;
use Zend\Authentication\AuthenticationService;
use Zend\ServiceManager\Factory\FactoryInterface;
use Zend\Db\Adapter\Adapter as DbAdapter;
use Zend\Authentication\Adapter\DbTable\CredentialTreatmentAdapter as AuthAdapter;
use Zend\Authentication\Storage\Session as Storage;
class AuthenticationServiceFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$controllerPluginManager = $container;
$serviceManager = $controllerPluginManager->get('ServiceManager');
$config = $serviceManager->get('configuration');
$dbAdapter = new DbAdapter($config['db']); // Mysqli driver working in other modules
$authAdapter = new AuthAdapter($dbAdapter);
$authAdapter->setTableName('user')->setIdentityColumn('username')->setCredentialColumn('password');
$storage = new Storage();
return new AuthenticationService($storage, $authAdapter);
}
}
Here is my module/User/src/Module.php
file
namespace User\Service;
use Zend\Mvc\MvcEvent;
use Zend\Authentication\Adapter\DbTable\CredentialTreatmentAdapter;
class Module
{
public function getConfig()
{
return include __DIR__ . '/../config/module.config.php';
}
public function onBootstrap(MvcEvent $e)
{
$services = $e->getApplication()->getServiceManager();
$auth = $services->get(AuthenticationServiceFactory::class);
// Returns Fatal error: Call to undefined method Zend\Authentication\AuthenticationServiceFactory::setIdentity()
// $auth is an AuthenticationServiceFactory object and not the AuthenticationService returned by its __invoke() function
$this->authAdapter->setIdentity('dummy_user_name');
$this->authAdapter->setCredential('dummy_password');
print_r($this->authAdapter->authenticate());
}
}
Any ideas ?
As usual, when I find the answer by myself, I post it here en case it may help someone.
module/User/config.module.php
namespace User;
use Zend\Router\Http\Literal;
use Zend\Router\Http\Segment;
use Zend\ServiceManager\Factory\InvokableFactory;
return [
'router' => [...],
'controllers' => [...],
'service_manager' => [
'factories' => [
'auth-service' => Service\AuthenticationServiceFactory::class,
],
],
];
module/User/src/Service/AuthenticationServiceFactory.php
namespace User\Service;
use Interop\Container\ContainerInterface;
use Zend\Authentication\AuthenticationService;
use Zend\ServiceManager\Factory\FactoryInterface;
use Zend\Db\Adapter\Adapter as DbAdapter;
use Zend\Authentication\Adapter\DbTable\CredentialTreatmentAdapter as AuthAdapter;
use Zend\Authentication\Storage\Session as Storage;
class AuthenticationServiceFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
// Get data from config files.
$controllerPluginManager = $container;
$serviceManager = $controllerPluginManager->get('ServiceManager');
$config = $serviceManager->get('configuration');
// or we can simplify these 3 lines using the following
//$config = $container->get('configuration');
// Configure DbAdapter with set-up information from config files.
$dbAdapter = new DbAdapter($config['db']); // Mysqli driver working in other modules
// Configure AuthAdapter with DbAdapter.
// See https://docs.zendframework.com/zend-authentication/adapter/dbtable/credential-treatment/
$authAdapter = new AuthAdapter($dbAdapter);
$authAdapter->setTableName('user')->setIdentityColumn('username')->setCredentialColumn('password');
// Configure session storage.
$storage = new Storage();
// Return AuthenticationService.
return new AuthenticationService($storage, $authAdapter);
}
}
module/User/src/Module.php
namespace User\Service;
use Zend\Mvc\MvcEvent;
use Zend\Authentication\Adapter\DbTable\CredentialTreatmentAdapter;
class Module
{
public function getConfig()
{
return include __DIR__ . '/../config/module.config.php';
}
public function onBootstrap(MvcEvent $e)
{
// Get the service manager.
$services = $e->getApplication()->getServiceManager();
// Set event to retrieve user's identity for every request.
$eventManager = $e->getApplication()->getEventManager();
$eventManager->attach(MvcEvent::EVENT_ROUTE, array($this, 'protectPage'), -100);
}
public function protectPage(MvcEvent $event)
{
$match = $event->getRouteMatch();
if (! $match) {
// We cannot do anything without a resolved route.
return;
}
// Get AuthenticationService and do the verification.
$services = $event->getApplication()->getServiceManager();
$authService = $services->get('auth-service');
// If user does not have an identity yet.
if (! $authService->hasIdentity()) {
// Do what you want like routing to login page...
}
}
}
My problem was that setting user's identity and credential was not supposed to be done here but rather in a login()
function somewhere else. In the Module Class
we just need to check the identity.