ZF2,创建侦听器和会话验证失败时引发异常
ZF2, exception was raised while creating a listener & Session validation failed
让我们从问题所在开始:我有一个与 "route" 事件耦合的 acl 侦听器,它起初似乎工作正常,但一段时间后会抛出几个错误。这些是错误:
Fatal error: Uncaught exception
'Zend\Session\Exception\RuntimeException' with message 'Session
validation failed'...
Zend\ServiceManager\Exception\ServiceNotCreatedException: An exception
was raised while creating "authService"; no instance returned...
Zend\ServiceManager\Exception\ServiceNotCreatedException: An exception
was raised while creating "MyAclListener"; no instance returned...
侦听器设置如下:
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') ,
);
}
}
会话已在 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' )
) ,
) ,
) ,
)
了解错误后我的 "identity" 丢失并且登录用户已注销可能也很有用。
那么,我做错了什么?我如何摆脱这些错误?甚至:是否有更好的解决方案来设置 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 ) 已移动,因此它现在仅在登录时发生。
您向 AclListenerFactory
中的 ServiceLocator
询问 authService
,但它找不到这样命名的任何内容,这会导致第二个异常。
因为 authService
未找到,所以您的工厂没有 return 侦听器。那是最后一个例外。
在你的代码中你写:
$serviceLocator->get('authService') ,
第一个异常与某些会话验证失败有关。所有问题的原因可能就在那里。没有会话验证可能导致无效 authService
从而链接其他两个异常。
这个 authService
是在哪里注册或创建的?这在您当前共享的代码中不可见。以及该服务如何依赖失败的 "validation"...
如果您解决了会话验证问题,一切可能都会好起来。
我严重怀疑这是 "best practice",但是从我的侦听器的构造函数中删除,那些依赖于会话的依赖项(自最初的问题以来添加了更多)解决了这个问题。我知道在我的代码中需要它们的第一刻就从 ServiceLocator 获取它们并将它们存储在我的侦听器 class 的受保护参数中以供进一步使用。然而,正如我所说,这不再是正确的依赖注入,但至少它有效。
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');
....
}
让我们从问题所在开始:我有一个与 "route" 事件耦合的 acl 侦听器,它起初似乎工作正常,但一段时间后会抛出几个错误。这些是错误:
Fatal error: Uncaught exception 'Zend\Session\Exception\RuntimeException' with message 'Session validation failed'...
Zend\ServiceManager\Exception\ServiceNotCreatedException: An exception was raised while creating "authService"; no instance returned...
Zend\ServiceManager\Exception\ServiceNotCreatedException: An exception was raised while creating "MyAclListener"; no instance returned...
侦听器设置如下:
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') ,
);
}
}
会话已在 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' )
) ,
) ,
) ,
)
了解错误后我的 "identity" 丢失并且登录用户已注销可能也很有用。
那么,我做错了什么?我如何摆脱这些错误?甚至:是否有更好的解决方案来设置 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 ) 已移动,因此它现在仅在登录时发生。
您向 AclListenerFactory
中的 ServiceLocator
询问 authService
,但它找不到这样命名的任何内容,这会导致第二个异常。
因为 authService
未找到,所以您的工厂没有 return 侦听器。那是最后一个例外。
在你的代码中你写:
$serviceLocator->get('authService') ,
第一个异常与某些会话验证失败有关。所有问题的原因可能就在那里。没有会话验证可能导致无效 authService
从而链接其他两个异常。
这个 authService
是在哪里注册或创建的?这在您当前共享的代码中不可见。以及该服务如何依赖失败的 "validation"...
如果您解决了会话验证问题,一切可能都会好起来。
我严重怀疑这是 "best practice",但是从我的侦听器的构造函数中删除,那些依赖于会话的依赖项(自最初的问题以来添加了更多)解决了这个问题。我知道在我的代码中需要它们的第一刻就从 ServiceLocator 获取它们并将它们存储在我的侦听器 class 的受保护参数中以供进一步使用。然而,正如我所说,这不再是正确的依赖注入,但至少它有效。
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');
....
}