首页 文章

ZF3 MVC Zend \身份验证即服务工厂

提问于
浏览
1

我正在尝试将我的ZF2 User 模块改编为ZF3 MVC . 它有一个身份验证服务管理器,在 Module 类中的 onBootsrap 函数中为每个请求(即页面加载)调用,以检查用户是否经过身份验证 .

由于 serviceLocatorServiceAware 不再可用,我正在尝试创建 AuthenticationServiceFactory 但我还没有成功 . 您对我的错误以及如何使用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());
    }
}

有任何想法吗 ?

2 回答

  • 3

    像往常一样,当我自己找到答案时,我在这里发布它可以帮助某人 .

    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...
            }
        }
    }
    

    我的问题是设置用户的身份和凭证不应该在这里完成,而是在其他地方设置 login() 功能 . 在 Module Class 中我们只需要检查身份 .

  • 1

    我赞同你自己的答案,因为我认为这是一个很好的答案,但也许这会改善数据库连接 .

    您写道,您已经有一个Mysqli驱动程序与另一个模块一起工作 . 如果在用户表的另一个模块中有一个存储库,则可以使用它并使用自定义适配器简化代码 . 假设您的用户存储库实现 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));
        }
    }
    

    你的 AuthenticationServiceFactory 成了:

    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;
        }
    }
    

    注册您的工厂: 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...
    ];
    

相关问题