在我们的Intranet应用程序中,我们使用SSO(单点登录)登录,而客户端和auth源应用程序上的会话都存储在memcached中。
会话设置为在垃圾收集器可能将其视为删除之前的12小时。这两个应用程序都是使用ZF2编写的。
不幸的是,问题是,在一段时间后(我没有确切的值),浏览器会丢失导致重定向到auth origin的会话,其中会话仍处于活动状态,因此用户被重定向返回客户端并刷新浏览器会话。如果用户没有未保存的工作,这不是什么大问题,因为这两个重定向在1秒内发生,用户甚至可能不会注意到它们。
但是当用户有未保存的工作时,这确实是一件大事,即使尝试保存它也会导致重定向,工作也就消失了。
以下是Bootstrap.php
中会话的配置:
class Module
{
public function onBootstrap(MvcEvent $e)
{
// ...
$serviceManager = $e->getApplication()->getServiceManager();
$sessionManager = $serviceManager->get('session_manager_memcached');
$sessionManager->start();
Container::setDefaultManager($sessionManager);
// ...
}
public function getServiceConfig()
{
return array(
'factories' => array(
// ...
'session_manager_memcached' => function ($sm) {
$systemConfig = $sm->get('config');
$config = new SessionConfig;
$config->setOptions(array(
'phpSaveHandler' => 'memcache',
'savePath' => 'tcp://localhost:11211?timeout=1&retry_interval=15&persistent=1',
'cookie_httponly' => true,
'use_only_cookies' => true,
'cookie_lifetime' => 0,
'gc_maxlifetime' => 43200, // 12h
'remember_me_seconds' => 43200 // 12h
));
return new SessionManager($config);
},
// ...
);
}
}
身份验证服务定义为
'authService' => function ($sm) {
$authService = new \Zend\Authentication\AuthenticationService;
$authService->setStorage(new \Zend\Authentication\Storage\Session('user_login'));
return $authService;
},
然后在应用程序中的任何地方都需要检索或设置会话值我只需使用\Zend\Session\Container
这样:
$sessionContainer = new \Zend\Session\Container('ClientXYZ');
$sessionContainer['key1'] = $val1;
// or
$val2 = $sessionContainer['key2'];
在会话中使用来自auth origin的PHPSESSID的令牌,在活动会话中请求SSO。在这个问题中描述这个很复杂。
此外,身份验证服务还使用相同的设置在memcached会话中存储用户身份(具有ACL的角色)。显然,现在这是造成混乱的地方。显然,身份验证服务的会话存储过早地超时导致ACL不检索用户身份以检查导致SSO注销序列(但由于用户没有真正注销,SSO如上所述重新定向用户)。 p>
我不确定我(也可以)在这里分享多少代码,也许您可以立即引导我解决问题,或者只是问我一些问题。经过数小时的调试并试图找出问题后,我现在很无助。
在某个地方,我已经读过,当会话 cookie 的大小达到1MB时,memcached会擦掉内存 - 可能是这种情况吗?对于用户身份,我们只保存一般用户信息和角色阵列,我猜这可能是最大的。高达几kb ......
编辑1:为了驳回所有猜测并节省您的时间,这里有一些事实(为了留意):
PHPSESSID
,它的值是存储数据的memcached中内存块的关键我将在PHP中实现一些die
,在JS部分中实现return
以捕获会话被认为已经消失的时刻,并进一步检查浏览器cookie,memcached数据等。会更新你(除非有人提供解释和解决方案)。
答案 0 :(得分:1)
使用memcached
作为session.save_handler
时,会话的垃圾收集将不。
因为Memcached使用TTL(生存时间)值,所以不需要垃圾回收。没有足够长的时间达到TTL年龄的条目将被视为“新鲜”并将被使用。之后它将被视为“陈旧”,并且不将被再次使用。最终Memcached将释放条目使用的内存,但这与PHP的会话垃圾收集无关。
实际上,在这种情况下实际使用的唯一session.gc_
设置是session.gc_maxlifetime
,它将作为TTL传递给Memcached。
简而言之:在您的情况下,垃圾收集不是问题。
当您使用Memcached作为会话的存储时,操作系统提供的任何手动清理磁盘上的会话文件夹(如Ubuntu)的cronjobs将无效。 Memcached是内存存储,而不是磁盘存储。
简而言之:像你这样的cronjobs不是你的问题。
您声明SSO服务器/授权与SSO客户端(应用程序本身)在同一台计算机上,使用相同的Web服务器/ PHP配置,并使用相同的Memcached实例。
这让我相信我们必须在应用程序中搜索会话管理的方式,因为这是SSO权限和客户端之间的唯一区别。换句话说:我们需要深入了解Zend \ Session。
免责声明:我专业从事过几个Zend Framework 1应用程序,但没有在任何Zend Framework 2应用程序上工作。所以我在这里失明:)
我在您的配置中注意到的一件事是您已将cookie_lifetime
设置为0
。这实际上意味着“直到浏览器关闭”。这与remember_me_seconds
设置为12小时并不合理,因为很多人会在此之前关闭浏览器。
我建议您将cookie_lifetime
设置为12小时。
另请注意,remember_me_seconds
仅在实际使用“记住我”功能时使用。换句话说:如果调用Zend\Session\SessionManager::rememberMe()
。
看看你使用Memcached作为会话存储实现的方式,以及我在这个主题上可以找到的内容,我会说你做了一些与“首选方式”不同的东西。
关于此主题的大多数资源建议使用Zend\Session\SaveHandler\Cache
(doc,api)作为保存处理程序,这使您能够使用Zend\Cache\Storage\Adapter\Memcached
({{3 },doc)。这使您可以更好地控制正在发生的事情,因为它不依赖于有限的memcached
会话保存处理程序。
我建议你试试这个实现。如果它不能立即解决您的问题,则至少需要更多资源才能找到该主题。你找到解决方案的机会会更好恕我直言。
答案 1 :(得分:1)
package main
import "fmt"
func main() {
k := 6
switch k {
case 4: fmt.Println("was <= 4"); fallthrough;
case 5: fmt.Println("was <= 5"); fallthrough;
case 6: fmt.Println("was <= 6"); fallthrough;
case 7: fmt.Println("was <= 7"); fallthrough;
case 8: fmt.Println("was <= 8"); fallthrough;
default: fmt.Println("default case")
}
}
这是我用来为X用户创建cookie的函数。无论是否有重定向或用户是否关闭了浏览器,cookie都会存在3个小时。它还在那里。只需在Module.php中的onBootstrap()方法中调用此函数。
在记录时,我使用ZF2 AuthenticationService和Container来存储和检索用户数据。
我建议您安装这些模块以便于调试。 https://github.com/zendframework/ZendDeveloperTools https://github.com/samsonasik/SanSessionToolbar/
答案 2 :(得分:0)
这个答案可能无法立即解决memcache问题的原因,但由于memcache的不可靠性,我建议在一些持久存储中备份memcached数据。 记忆数据将帮助您提高应用程序的性能,但它不是故障安全的。
也许你可以在AuthenticationService
实例中建立一个后备(持久)存储。然后首先尝试从memcache中获取身份验证数据,如果没有找到任何内容,则检查持久存储中是否有可用的内容。
这至少可以解决所有意外的memcache丢失问题。