ZF3 MVC Zend \ Authentication as a Service Factory

I am trying to adapt the ZF2 User module to ZF3 MVC. It has an authentication service manager, which is called in the onBootsrap function inside the Module class for each request (for example, loading a page) to check if the user is verified.

Since serviceLocator and ServiceAware no longer available, I'm trying to create an AuthenticationServiceFactory , but have failed so far. Have you had any ideas on what I am doing wrong, and how can I do this 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?

+1
source share
2 answers

As usual, when I find the answer myself, I post it here if it can 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 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 the user ID and credentials should not have been done here, but rather in the login() function somewhere else. In the Module Class we just need to verify the identity.

+2
source

I supported your own answer because I think it is good, but maybe this will improve it for connecting to DB.

You wrote that you already have a Mysqli driver that works with another module. If you have a repository in this other module for a user table, you can use it and simplify the code using a custom adapter. Suppose your user repository implements User\Model\UserRepositoryInterface :

 namespace User\Model; interface UserRepositoryInterface { public function getUser($id); public function updateUser(User $user); // other methods... } 

Module\src\Factory\CustomAdapterFactory.php

 namespace User\Factory; use Interop\Container\ContainerInterface; use User\Adapter\CustomAdapter; use User\Model\UserRepositoryInterface; use Zend\ServiceManager\Factory\FactoryInterface; class CustomAdapterFactory implements FactoryInterface { public function __invoke(ContainerInterface $container, $requestedName, array $options = null) { return new CustomAdapter($container->get(UserRepositoryInterface::class)); } } 

Your AuthenticationServiceFactory will become:

 namespace User\Factory; use Interop\Container\ContainerInterface; use User\Adapter\CustomAdapter; use Zend\Authentication\AuthenticationService; use Zend\ServiceManager\Factory\FactoryInterface; use Zend\Authentication\Storage\Session as SessionStorage; class AuthenticationServiceFactory implements FactoryInterface { public function __invoke(ContainerInterface $container, $requestedName, array $options = null) { $authService = new AuthenticationService(); $storage = new SessionStorage(); $authService->setStorage($storage); $authService->setAdapter($container->get(CustomAdapter::class)); return $authService; } } 

Register your factories: module/User/config.module.php

 namespace User; use User\Factory\AuthenticationServiceFactory; use User\Factory\CustomAdapterFactory; use User\Factory\UserRepositoryFactory; use Zend\Authentication\AuthenticationService; return [ 'service_manager' => [ 'aliases' => [ Model\UserRepositoryInterface::class => Model\UserRepository::class ], 'factories' => [ Model\UserRepository::class => UserRepositoryFactory::class, Adapter\CustomAdapter::class => CustomAdapterFactory::class, MailService::class => MailServiceFactory::class, AuthenticationService::class => AuthenticationServiceFactory::class, ] ], // etc... ]; 
+1
source

Source: https://habr.com/ru/post/1237536/


All Articles