这段时间,开发一个门户网站的SSO集成,没想到最后部署时,被一个问题折磨了两天:在我机器上测试好的Java SSO服务器端应用和他们的PHP discuz论坛SSO集成时,总是Session丢失。
我的开发环境:
SSO应用负责登录和退出,以及账号同步的Web Services(REST方式),它部署在WebLogic8.14上,WebLogic上还有其它Java Web应用需要集成。Discuz论坛必须集成到SSO。
SSO部署到本机的WebLogic,并且php论坛也部署在本机。
客户那边的环境:
WebLogic和Discuz在不同的机器上,当然也是不同IP,或是不同域名。另外,他们的论坛在一个frameset里面。
本来家里测试完好,但在客户现场部署时,失败:登录成功后跳转总是显示未登录状态,但是,抛开frameset登录,有时候ok。
于是,回公司后,向客户要了他们的Discuz论坛的所有代码,因为第一次部署时,发现他们对论坛改动很大,代码发过来后,在本机部署,没有任何问题,包括frameset里面!
我当时怀疑是Weblogic两边环境有区别,不过差别很小,都是8.1*版本。于是,第二次我去了客户那边,并且带去了自己的笔记本,上面有开发测试好的程序。
到了客户那边,我就在他们那个安装了WebLogic服务器的机器上,再安装了一个我自己的Weblogic,一切安装、部署完毕:问题依然存在!
我一步步确定是frameset引起的问题。但是,登录时,有filter拦截跳转,登录Weblogic成功后跳转,登录Discuz passport后也跳转。问题全部搅混在一起,就很难确定问题究竟出在哪里。
后来,log出request.getRemoteUser,总是返回null,我基本上确定是session所必须的cookie丢失造成的,但为什么会丢失呢?不就是在一个frameset里面吗?不用frameset,确实不出问题。
但是,在本机测试时,无论用frameset与否,都不出问题啊?
反复推敲,估计是不同域名或IP,再加上frameset,就会出问题,但问题怎么描述呢?也就是说,什么具体的条件,会引起cookie丢失呢?
说实话,这个时候,最难的,就是确定真正的问题出在哪里。
于是,我google了一下:“frameset cookie”,竟然有很多人讨论!不久就基本上确认了我当时推测。IE6.0对W3C 关于cookie的P3P协议的支持,支持得有些荒唐,几乎成了bug。
我再用firefox测试了SSO登录和退出,一切ok!然后,设置一下IE的cookie隐私,也一切ok,不用对程序做任何改动。但是,总不能要求几十万用户这么做吧。
问题很快就得到了解决。
还是描述一下具体的问题吧:
在frameset里面,也就是里面的frame是来自第三方站点(不同IP或不同域名),那么默认情况下IE会自动禁用这些站点的cookie,也就是在请求某url时在HTTP header里不发送它们的cookie,包括session的cookie。注意,这些站点在response里面设置的cookie还是会被发送到浏览器的。
那么,解决的办法,自然是对frame里面的第三方站点的response header里面添加一个确认信息,在MSDN里面有个最简单的解决办法:response.addHeader("P3P","CP=CAO PSA OUR")。
我当时是在可能的servlet的response里面添加,不过,最简单的办法,是用一个filter,对所有路径下的uri,都设置response.setHeader("P3P","CP=CAO PSA OUR")。
我自己单独测试时,发现只要有某个http header设置了上面那个header信息,以后cookie都会畅通无阻。但是,设置html的meta没用。
上面控制cookie的方法,和以前的方法很不一样。第一,它不是操作cookie本身。第二,它是在cookie之外控制cookie。第三,它不是set cookie,而是控制cookie是否随着请求发送(是否拦截cookie)。
下面几篇文章描述了这个问题,并且提出了解决方案:
http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q323752 (解决方案)
http://msdn.microsoft.com/workshop/security/privacy/overview/privacyie6.asp (P3P和IE隐私关系)
http://www.castlecops.com/a837-P3P_in_IE6_Frustrating_Failure.html (评价非常有意思)
我认为,MS官方给出的example还不是很好,因为我认为frame里面应该有两个页面:发起session页面和接收session页面,我给出了自己的例子,在附件里面。
另外,如果你需要模拟两个IP,你可以在本机建立一至两个微软的LoopBack 网卡(控制面版->添加新硬件)。
然后在IIS里面用一个IP建立一个站点,在Tomcat里面用另外一个IP。
website.rar | ||
描述: | 本文的测试代码。 | ![]() 下载 |
文件名: | website.rar | |
文件大小: | 3 KB | |
下载过的: | 文件被下载或查看 33 次 |