`
wengcang
  • 浏览: 14330 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

第三方支付过程中session失效/session跨域问题

阅读更多

        问题产行于公司p2c交易平台的一个用户充值模块。

 

        平台简介:该平台通过第三方支付(以下使用“支付宝”代替)完成与各大银行的交易(充值、投资、转帐、提现等操作),并将数据保存在我司的服务器数据库中,服务器使用tomcat,数据库Mysql

 

        平台充值流程:用户登陆系统----点击充值-----跳转到支付宝----登陆支付宝------选择银行------充值完毕-----redrect到用户中心(平台中的action为"preurl:/user/center"),问题来了,

 

当用户充值完成后转回用户中心时平台转回了登陆界面,需要用户重新输入一次用户名和密码才能到达用户中心。

 

        谈到此种现象,但凡搞过java开发的软件工程师应该都能想到是session问题,好吧,让我们来一起研究一下从点击充值到支付完成过程中session的变化。

 

        1、用户使用username 和 password登陆后会将用户信息保存在session中,并且在客户端浏览器的cookie中添加一个cookie(key:JSESSIONID,value:XXX);

 

        2、用户点击充值按钮跳转到支付宝---XX银行进行充值,由于XX银行充值网站也是使用tomcat,那么cookie中默认的session key 也为 JSESSIONID,这样以来充值完毕便修改了cookie中session的值;

 

        3、平台使用spring security的用户登陆校验,拦截所有需要用户登陆的界面,这样以来,当充值完成返回preurl:/user/center的时候被spring拦截,并取出cookie中JSESSIONID所对应的值再去session里查找用户信息;

 

        4、由于XX银行修改过的session与原session并非同一session,于是spring将其拦截到用户登陆界面;

 

        以上便是一个很常见的跨域访问session失效问题,但是问题并非想象中那么简单,至少笔者在此问题上费了很大的力气,并寻问“众大神”以及几千人的技术群,无一人知晓(或许真正的大神不屑一顾吧),现解决办法及说明总结如下:

 

        1、总体思路

              在用户点击充值时将sessionid保存下来,充值成功后再将sessionid取出来替换

 

        2、具体实现

 

               支付宝接口说明中有一个字段叫做merpri(私有域),官方解释:“用户自定义字段,可以将自己需要

的信息保存在里面,接口调用完成后原样返回”,那么正好是我们需要的,在向支付宝write数据时,我将sessionid取到并放入merpri中,然后在回调时将merpri中的值取出,通过遍历cookie数组将数组中名为JSESSIONID的cookie替换为之前的,关键代码如下:

 

 

//说明:以下代码为直接在博客中手写如有错误请留言,以便及时更正
//从jsf中获取
HttpServletRequest request = FacesUtil.getHttpServletRequest ();
HttpServletResponse response = FacesUtil.getHttpServletResponse();
//从支付宝返回参数中获取之前保存的sessionid
String finalSession = request.getParameter("merpri");
Cookie[] cookies = request.getCookies();
for(Cookie c : cookies){
     if(c.getName.equals("JSESSIONID")){
         //如果是带域名的网站需要配置,因为现在的问题是跨域session失效
         c.setDomain(".alibaba.com");     
          //删除cookie
         c.setMaxAge(0);
         //设置路径(域名后面的主路径)
         c.setPath("/alibaba");
         response.addCookie(c);
         c.setDomain(".alibaba.com");
         Cookie cookie = new Cookie("JSESSIONID",finalSession);
         //设置生命周期为20分
         cookie .setMaxAge(20);
         cookie .setPath("/");
         response.addCookie(cookie);
     }
}

         3、容易出问题的地方总结:

 

 

             1)  不要将代码放在耦合性较强的代码逻辑中

 

             2) cookie中sessionid的操作一定要在返回/user/center 之前最近位置(否则将无法删除cookie)

 

             3) cookie生命周期和路径一定要注意匹配,应当使用调试工具查看cookie实时的一个值

 

             4) 设置domain时需要特别注意,经本人测试以下四种浏览器:ie 9, firefox, 360安全, 猎豹

 

       其中ie 9 和 firefox域为 .alibaba.com  而360安全,猎豹 的域为www.alibaba.com这样就会出现:使用不同的浏览器设置cookie的域不同而导致其中2个浏览器依然无法正常跳转到用户中心,解决办法:在代码中判断其内核,根据不同的内核设定不同的域。

                          5) 若使用的第三方支付没有私有域的概念,那么请使用数据库代替吧,即:将sessionid放入数据库中,这样以来要保证事务的完整性了

 

题外话:

 

(谈到浏览器的兼容问题,IE浏览器不得不让人大跌眼镜,众所知周,所谓“浏览器兼容”无非就是IE这个“笨重的家伙”,解析js速度慢到极点,并且效果看上去极差,这一点应该向谷歌和火狐学习),360有个新功能是这样描述的:

 

         我们新增加了一个控制手段:内核控制Meta标签。只要你在自己的网站里增加一个Meta标签,告诉360浏览器这个网址应该用哪个内核渲染,哪么360浏览器就会在读取到这个标签后,立即切换对应的内核。并将这个行为应用于这个二级域名下所有网址。

目前该功能已经在所有的360安全浏览器实现。我们也建议其它浏览器厂商一起支持这个实现。让这个控制标签成为行业标准。

在head标签中添加一行代码:

 

<html>
  <head>
    <meta name="renderer" content="webkit|ie-comp|ie-stand">
  </head>
  <body>
  </body>
</html>

 

 

        浏览器的兼容问题严重困扰了众多的软件工程师,不仅仅是前端开发,在此希望能够出台一个浏览器标准将所有的浏览器内核规范处理,开发工程师使用这个规范去开发,以减少这种“由于浏览器间客户流量竞争”而给开发者带来的工作量。

            

0
4
分享到:
评论
17 楼 wengcang 2015-05-15  
webeasymail 写道
看到这个帖子,我不得不吐槽一下,不知道怎么会得出这样的结论!

发这篇也希望提供宝贵建议,尽情地带上你的理由来吐槽把
16 楼 wengcang 2015-05-15  
longfor5 写道
读的我很纳闷,作为第三方支付的技术人员,跟我们联调的商户从来没有出现过类似的问题,也没那么复杂去实现session共享。。。

每个平台的功能是不一样的
15 楼 wengcang 2015-05-15  
qingming.com 写道
看了楼上,我表示凌乱了。难道我以前学的cookie和session知识是错的,还是非标准的?

技术学的永远和实践的有差距,如果单单是查网上的回答搞定的,我也不发了
14 楼 wengcang 2015-05-15  
Vampiredx 写道
以前做过和Paypal的集成,也遇到session失效的问题。但原因是为了保证安全,使用的内存cookie。这样跨域跳转后,内存cookie保存的sessionId找不到了。所以解决方案是跳转前临时把sessionId写入磁盘,跳转回来以后还能找到sessionId。接着再把sessionId从磁盘删掉,重新放到内存里面。


是的,写入磁盘也是可以的,由于我们的第三方支付里面提供了这个私有域,这样做的操作比较少
13 楼 wengcang 2015-05-15  
liubey 写道
银行还能将别人服务器里的session改了,我真是日了狗了,头一次听说这么牛逼的事情。那还要黑客干嘛,别黑了,直接改session吧

跳转到银行的时候由于是跨域,并且在银行那边你的sessionid肯定是与原来的不一样的,之所以“修改”了以前的session,是因为,大量用户的需求,要求在支付完成后,在银行页面直接跳转回到网站用户中心,因此,我们需要保存原来的session
12 楼 wengcang 2015-05-15  
qingming.com 写道
从楼主的分析觉得楼主技术不错。但有点混乱。
你可能是网站和支付后回调网站域名不同吧。如网站是a.xxxx.com,回调是b.xxxx.com。这样两个网站的cookie是分开的。这种情况你需要的是单点登录。登录成功后记一个自定义的共享cookie到xxxx.com域(如sso_ticket),系统拦截的时候如果jessessionid是未登录的,则检测有没有单点登录cookie,有就判断是否是真实存在的,存在代表成功。

网站和支付回调的域名是相同的,在跳转到第三方支付的时候,session是存在的,而到银行的时候会将jsessionid的值改变,因此,某些第三方支付给我们提供了一个私有域,目的就是为了让我们保存自己的东西,然后原样返回,比如sessionid
11 楼 qingming.com 2015-05-15  
看了楼上,我表示凌乱了。难道我以前学的cookie和session知识是错的,还是非标准的?
10 楼 Vampiredx 2015-05-15  
以前做过和Paypal的集成,也遇到session失效的问题。但原因是为了保证安全,使用的内存cookie。这样跨域跳转后,内存cookie保存的sessionId找不到了。所以解决方案是跳转前临时把sessionId写入磁盘,跳转回来以后还能找到sessionId。接着再把sessionId从磁盘删掉,重新放到内存里面。

9 楼 qingming.com 2015-05-15  
从楼主的分析觉得楼主技术不错。但有点混乱。
你可能是网站和支付后回调网站域名不同吧。如网站是a.xxxx.com,回调是b.xxxx.com。这样两个网站的cookie是分开的。这种情况你需要的是单点登录。登录成功后记一个自定义的共享cookie到xxxx.com域(如sso_ticket),系统拦截的时候如果jessessionid是未登录的,则检测有没有单点登录cookie,有就判断是否是真实存在的,存在代表成功。
8 楼 longfor5 2015-05-15  
读的我很纳闷,作为第三方支付的技术人员,跟我们联调的商户从来没有出现过类似的问题,也没那么复杂去实现session共享。。。
7 楼 webeasymail 2015-05-14  
看到这个帖子,我不得不吐槽一下,不知道怎么会得出这样的结论!
6 楼 wengcang 2015-05-14  
vickatxmu 写道
为何你的站点和银行站点的cookie是会共享呢? cookie不是有domain和path来区别

跳转到第三方支付时不会出现session失效的问题,到银行的时候,银行将session修改了,然后redrect回来的时候会获取最新的session
5 楼 wengcang 2015-05-14  
030710314 写道
1楼说的对,站点的cookie不会共享的!你的问题应该是用户在支付宝停留时间太长,导致回退到你的网站的之后session过期失效导致的。其实对于这种对接第三方支付的时候,为啥一定要用session来控制呢?无状态的最好。

平台已经上线很久了,他的代码逻辑我几乎没看,就开始写功能和修复bug了
4 楼 wengcang 2015-05-14  
liubey 写道
看博客描述,博主技术应该还算可以吧。。。怎么连你的站点与银行站点cookie和session不可能共享这么简单的事儿都不知道呢,还煞有介事的分析了好长时间。
另外我觉得问题你的问题有两种可能:
一个是用户停留过久,seesion失效
另外一个是充值发起域名与支付宝回调url域名不匹配,导致session和cookie没共享,比如你在www.abc.com发起充值,支付宝回调url却是abc.com的ip地址或者其他地址啥的

非用户停留过久,也非域名不匹配,这样我写这个才有意义,你明白吗?

3 楼 liubey 2015-05-14  
看博客描述,博主技术应该还算可以吧。。。怎么连你的站点与银行站点cookie和session不可能共享这么简单的事儿都不知道呢,还煞有介事的分析了好长时间。
另外我觉得问题你的问题有两种可能:
一个是用户停留过久,seesion失效
另外一个是充值发起域名与支付宝回调url域名不匹配,导致session和cookie没共享,比如你在www.abc.com发起充值,支付宝回调url却是abc.com的ip地址或者其他地址啥的
2 楼 030710314 2015-05-14  
1楼说的对,站点的cookie不会共享的!你的问题应该是用户在支付宝停留时间太长,导致回退到你的网站的之后session过期失效导致的。其实对于这种对接第三方支付的时候,为啥一定要用session来控制呢?无状态的最好。
1 楼 vickatxmu 2015-05-14  
为何你的站点和银行站点的cookie是会共享呢? cookie不是有domain和path来区别

相关推荐

    iframe跨域与session失效问题的解决办法

    第三方session/cookie指的是当前访问的网站中会加载(嵌入)另外第三方的网站代码,例如促销广告,那么第三方网 站也会在访客的计算机上添加session/cookie,这种就是第三方session/cookie。 我的问题 在开发讯息...

    完美解决ajax访问遇到Session失效的问题

    最近由于一个项目,模块切换为ajax请求数据,当Session失效后,ajax请求后没有返回值,只有响应的html:&lt;html&gt;[removed]window.open(‘http://192.168.0.118:8080/welcomeAction/loginUI.do’,’_top’);...

    【ASP.NET编程知识】iframe跨域与session失效问题的解决办法.docx

    【ASP.NET编程知识】iframe跨域与session失效问题的解决办法.docx

    nginx反向代理导致session失效的问题解决

    一同事求援:后台系统的登录成功了,但不能成功登进系统,仍然跳转到登录页,但同一套代码另一个环境却没有问题。 背景 经了解,他对同一个项目使用tomcat部署了两个环境,一个在开发服务器上,一个在他本机,两个...

    解决前后端分离 vue+springboot 跨域 session+cookie失效问题

    环境: 前端 vue ip地址:192.168.1.205 ...搜索问题,发现跨域,服务器响应的setCookie浏览器无法保存,而且就算保存了域名不同也不能携带。 第一步: 后台添加过滤器,因为前后端分离,不可能每个方

    express如何解决ajax跨域访问session失效问题详解

    主要给大家介绍了关于express如何解决ajax跨域访问session失效问题的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

    React如何解决fetch跨域请求时session失效问题

    主要给大家介绍了关于React如何解决fetch跨域请求时session失效问题的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    php中http与https跨域共享session的解决方法

    遇到了HTTP、HTTPS协议下session共享解决cookie失效的问题,这里提供一个临时解决办法。 实现原理:把session id设置到本地的cookie。 如下: 复制代码 代码如下: $currentSessionID = session_id(); session_id($...

    PHP关于IE下的iframe跨域导致session丢失问题解决方法

    今天搞的一个登录页面,被别的网站用iframe嵌进去后,死活无法登录(只在IE中存在这种情况)。 很明显,session无法被保存。但是直接在地址栏打开那个登录页面,一切都正常啊。真是奇怪啊。 在网上搜索了一下。发现...

    Yii2实现多域名跨域同步登录退出

    在平台开发过程中,项目分为前台(frontend)www.xxx.com和后台(backend) yun.xxx.com两部分,绑定两个域名, 我们知道在没有绑定域名的时候前后台可以同步登录和退出,但是绑定域名后就失效了,原因是session的作用...

    kisso单点登录

    kisso 采用的是加密会话 cookie 机制实现单点登录 SSO 服务,具备“无状态”、“分散验证” ... 3、cookie 轻松实现分布式服务部署,单点登录跨域访问等问题,换成 session 需要处理 session 复制及各种问题实现困难。

    ASP.NET.4揭秘 卷2

    n105 小结n第三部分 构建自定义控件 n第11章 构建自定义控件 n111 构建自定义控件概述 n1111 构建完全生成控件 n1112 构建组合控件 n1113 构建混合控件 n112 视图状态和控件状态 n1121 支持视图状态 n1122 支持控件...

Global site tag (gtag.js) - Google Analytics