【问题标题】:ZF2, exception was raised while creating a listener & Session validation failedZF2,创建侦听器时引发异常,会话验证失败
【发布时间】:2015-01-20 08:30:02
【问题描述】:

让我们从出了什么问题开始:我有一个与“路由”事件耦合的 acl 侦听器,它起初看起来工作正常,但一段时间后会引发一些错误。这些是错误:

致命错误:未捕获的异常 带有消息“会话”的“Zend\Session\Exception\RuntimeException” 验证失败'...

Zend\ServiceManager\Exception\ServiceNotCreatedException:一个异常 在创建“authService”时提出;没有返回实例...

Zend\ServiceManager\Exception\ServiceNotCreatedException:一个异常 在创建“MyAclListener”时提出;没有返回实例...

监听器设置如下:

class MyAclListener implements ListenerAggregateInterface
{
    /** @var  AuthenticationServiceInterface */
    protected $_authService;

    function __construct (
        AuthenticationServiceInterface $authService ,
    )
    {
        $this->_authService     = $authService;
    }

    public function attach ( EventManagerInterface $events )
    {

        $this->listeners[ ] = $events->attach( 'route' , array( $this , 'checkAcl' ) );
    }

    public function checkAcl( MvcEvent $e ) {
\\\Do Something for which the authService is needed
}

然后,在 module.config.php 我有

$config = array(
    'service_manager' => array(
        'factories' => array(
            'MyAclListener' => 'MyAcl\Factory\MyAclListenerFactory'
        ) ,
    ) ,
    'listeners'       => array(
        'MyAclListener'
    ) ,
);

监听器的工厂:

<?php

namespace MyAcl\Factory;

use MyAcl\Listener\MyAclListener;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class AclListenerFactory implements FactoryInterface
{

    public function createService(ServiceLocatorInterface $serviceLocator)
    {

        // Finally create the service
        return new MyAclListener(
            $serviceLocator->get('authService') ,
        );
    }

}

Session 在 Module.php 中设置

   public function onBootstrap ( MvcEvent $e )
    {

        $serviceManager         = $e->getApplication()->getServiceManager();

        $config = $serviceManager->get('Configuration');
        $this->initSession( $config['session'] , $serviceManager->get('sessionCache')  );
}

public function initSession ( $config , $cache )
{

    $sessionConfig = new SessionConfig();
    $sessionConfig->setOptions( $config );
    $sessionManager = new SessionManager( $sessionConfig );

    $saveHandler = new Cache($cache);
    $sessionManager->setSaveHandler( $saveHandler );

    $sessionManager->getValidatorChain()->attach('session.validate', array(new HttpUserAgent(), 'isValid'));
    $sessionManager->getValidatorChain()->attach('session.validate', array(new RemoteAddr(), 'isValid'));

    $sessionManager->start();
    $sessionManager->regenerateId(true);

}

这些是会话的相关配置:

$config = array(
    'session'         => array(
        'cookie_lifetime' => 28800 ,
        'remember_me_seconds' => 28800 ,
        'use_cookies'         => true ,
        'cookie_httponly'     => true ,
    ) ,
    'caches'          => array(
        'sessionCache' => array(
            'adapter' => array(
                'name'     => 'memcached' ,
                'lifetime' => 604800 ,
                'options'  => array(
                    'servers'    => array(
                        array(
                            '127.0.0.1' , 11211
                        )
                    ) ,
                    'namespace'  => 'MySessionCache' ,
                    'liboptions' => array(
                        'COMPRESSION'     => true ,
                        'binary_protocol' => true ,
                        'no_block'        => true ,
                        'connect_timeout' => 100
                    )
                ) ,
                'plugins'  => array( 'serializer' )
            ) ,
        ) ,
    ) ,
)

知道在错误之后我的“身份”丢失并且登录的用户被注销也可能很有用。

那么,我做错了什么?如何摆脱这些错误?甚至可能:是否有更好的解决方案来设置 ACL 检查和我的会话?

更新
我更改了会话设置:

在 Module.php 中

    public function onBootstrap ( MvcEvent $e )
    {

        $serviceManager = $e->getApplication()->getServiceManager();

        /* session */
        $this->expandInitialSessionConfig( $serviceManager , $serviceManager->get( 'sessionCache' ) );
}

public function expandInitialSessionConfig ( $sm , $cache )
{

    /** @var \Zend\Session\SessionManager $sessionManager */
    $sessionManager = $sm->get( 'Zend\Session\SessionManager' );

    $saveHandler = new Cache( $cache );
    $sessionManager->setSaveHandler( $saveHandler );

    $sessionManager->getValidatorChain()->attach( 'session.validate' , array( new HttpUserAgent() , 'isValid' ) );
    $sessionManager->getValidatorChain()->attach( 'session.validate' , array( new RemoteAddr() , 'isValid' ) );

}

在module.config.php中

return array(
    'session_config'  => array(
        'cookie_lifetime'     => 28800 ,
        'remember_me_seconds' => 28800 ,
        'use_cookies'         => true ,
        'cookie_httponly'     => true ,
        'gc_probability'      => 10 ,
        'gc_maxlifetime'      => 7200 ,
        'cookie_domain'       => 'mydomain.com' ,
    ) ,
    'service_manager' => array(
        'factories' => array(
            'Zend\Session\SessionManager'         => 'Zend\Session\Service\SessionManagerFactory' ,
            'Zend\Session\Config\ConfigInterface' => 'Zend\Session\Service\SessionConfigFactory' ,
        ) ,
);

并且 $sessionManager->regenerateId( true ) 被移动了,所以它现在只在登录时发生。

【问题讨论】:

    标签: php zend-framework2 listener


    【解决方案1】:

    您在AclListenerFactory 中向ServiceLocator 询问authService,但它找不到任何类似这样的名称,这会导致第二个异常。 因为找不到authService,所以您的工厂不会返回侦听器。这是最后一个例外。

    在您编写的代码中:

    $serviceLocator->get('authService') ,
    

    第一个异常与某些会话验证失败有关。所有问题的原因可能都在那里。没有会话验证可能导致没有有效的authService 从而链接其他两个异常。 这个authService 在哪里注册或创建?这在您当前共享的代码中不可见。以及该服务如何依赖失败的“验证”...

    如果你解决了你的会话验证问题,一切都会好起来的。

    【讨论】:

    • 在stackoverflow中输入错误时发生了错字,因为确实是一个错字。我通常会重命名我的课程等。此外,这样的错误会使它永远无法工作。它通常可以工作,但有时会因这些错误而失败。我目前正在考虑使用工厂设置我的会话。
    • authService 是通过 servicemanager 中的工厂注册的。它依赖于会话来存储身份。所以是的,问题可能是会话验证。这就是为什么我只是重新设计了那部分。到目前为止,没有更多的错误,但话又说回来,错误通常会在更长的时间内保持不存在。我还没有找到错误的模式。
    【解决方案2】:

    我严重怀疑这是“最佳实践”,但是从我的听众的构造函数中删除,那些依赖于会话的依赖项(自原始问题以来添加了更多)解决了这个问题。我知道在我需要它们的第一时间从 ServiceLocator 获取它们并将它们存储在我的侦听器类的受保护参数中以供进一步使用。然而,就像我说的,这不再是正确的依赖注入,但至少它有效。

    function __construct (Logger $_myLog )
    {
        $this->_myLog          = $_myLog;
        // removed here: $this->_authService     = $authService;
    
    }
    

    然后:

    public function checkAcl ( MvcEvent $e )
    {
       $sm = $e->getApplication()->getServiceManager();
       $this->_authService = $sm->get('authService');
       ....
    }
    

    【讨论】:

      猜你喜欢
      • 2021-03-11
      • 1970-01-01
      • 2013-06-22
      • 2023-03-07
      • 1970-01-01
      • 2016-05-15
      • 1970-01-01
      • 2020-01-26
      • 1970-01-01
      相关资源
      最近更新 更多