问题描述:在一个比较复杂的网站环境下。有多个产品向外提供服务。每一个产品下都有本身的用户登陆界面。如今须要设计一个统一的登陆界面。 当用户在这个界面登陆后就能够自由的使用各个产品和服务。同时意味着用户用一个账号能够在不一样服务里登陆,另外一方面就是在一个服务里面登陆后能够无障碍的 漫游到其余服务里面去。
实际应用:Sohu的Passport将focus.cn,17173.com,sogou.com,chinaren.com这四个域 名下的产品所有整合在一块儿了。用户在这四个站点中任何一个地方均可以登陆。当用户登陆后能够自由的使用其余域名下的服务。如今不少网站上都有bbs blog album服务。这些服务通常也是本身维护本身的用户信息。当发展到必定时候,也须要一个Passport机制整合全部服务,使用户能够单点登陆。
Sohu的实现方案在http://passport.sohu.com/ 登陆后 fiddler能够拦截到以下的返回信息:
因为passport.sohu.com的登陆界面使用了iframe隐藏提交。因此页面没有看到刷新。隐藏的iframe把用户名和加 密的password和其余信息发送给了passport.sohu.com。passport.sohu.com在Response中设置了成功登陆的 cookie。这个cookie能够证明这个用户成功登陆了passport.sohu.com。
当用户在Passport成功登陆后。客户端的Javascript根据成功登陆的标志,操做iframe请求 http://passport.sohu.com/sso/crossdomain_all.jsp?action=login 由于在同一个域名下,没有跨域,在此次请求中,上次成功登录的cookie会被一并带着回去。服务器端检查到成功登陆的cookie后会Render回一 段同时登陆多个站点的html。
这段html 要向4个地址发送请求。截至到如今都是在相同的Domain(passport.sohu.com)请求和返回,为真正的跨站点登陆作准备,真正的跨站点 登陆尚未开始。下面passport.sohu.com经过sso/crossdomain.jsp 在服务器端进行Redirect 设置http head 为302进行跳转。跳转后在这个跳转后的域名下设置登陆成功的cookie。这就是sohu实现跨站点登陆的核心过程。下面是 passport.sohu.com登陆17173.com的过程。
1. 经过http://passport.sohu.com/sso/crossdomain_all.jsp?action=login Render回来的script <script type="text/javascript" src="http://passport.sohu.com/sso/crossdomain.jsp?action=login&domain=17173.com"></script> 请求同域下的http://passport.sohu.com/sso/crossdomain.jsp?action=login& domain=17173.com 这时passport.sohu.com下成功登陆的cookie会被带回去。
2. 服务器看到成功登陆的Cookie后。在服务器端计算出一个加密后的17173.com的登陆Url,并Redirect到这个Url。
3. 17173.com从url的QueryString中取得信息。并在Response中设置Cookie。这个Cookie终于写到了 17173.com下。而不是passport.sohu.com下。从而使得用户在17173.com下登陆。其实用户在17173.com下手动登陆 也是写上一样的Cookie。之后用户再访问17173.com的页面时这个Cookie会被带回去。这就表示用户在17173.com下成功登陆过了。
通过上面的步骤。用户在passport.sohu.com下登陆的同时也在其余站点登陆了。
在上面的过程当中,最核心的技巧就是在指定的域下写入想要的Cookie:
1. Sohu使用了在同一个域名登陆后经过再次请求这个域名下某个连接后,获得要登陆站点的请求Url,经过javascript使隐藏的iframe请求要 登陆站点的Url,服务器端接到请求Redirect到要登陆站点,而后经过Response写入Cookie,完成跨域名写Cookie的操做。这种写 Cookie的方式,须要在跳转时对请求的QueryString进行加密。接受方须要对QueryString进行解密。
2. 这种作法在服务器端不须要特别的处理。只要写好相应Post操做 WriteCookie操做 Redirect操做就能够了。在FireFox下就能够正常工做了。可是在IE下写Cookie的操做还不行,老是写不进去Cookie。须要在Response中加入一段特别的Header. P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"
这个Http Header 是P3P安全的要求。P3P的详解 http://www.oreilly.com.cn/book.php?bn=7-302-07170-5 微软对这个的解释:http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q323752
一个更加轻量级的方案
Sohu的通行证方案已经能够轻松的将各个域名下的用户都同步登陆了。可是在实现上Sohu会让客户端的浏览器请求两次 passport.sohu.com。在第二次获得一个登陆多个站点的地址列表。在第三次请求时经过本域下的cookie进行身份验证,最后在服务器端跳 转到一个含有加密Key的其它域名的Url地址,最终写入登陆成功的Cookie。除去最开始的登陆,要求用户在登陆后再进行两次请求。而且服务器端要再 作一次跳转。Sohu的作法可能因为Sohu服务器环境和数据存储的结构所决定。
其实总共只需一次登陆请求,和每一个域名下一次请求就能够完成多站点登陆了,同时也不须要服务器端的跳转。
跨站点的请求由script的src发出。各个域名下的ssologin处理QueryString中的key,解密key,验证Key的合法性。在Response中写入登陆成功的Cookie。完成跨站点Cookie的写入。
两种方案的比较
1. Sohu使用的登陆方式,请求次数多,可是每次请求都有对应的验证过程,在服务端跳转时,重要的跳转Url地址在HttpHeader中,使得跳转地址更加安全,使得用户在跨域登陆时很是安全可靠。
2. 轻量级方案的登陆方式,请求次数少,没有服务器端的跳转,对服务器压力小。可是须要对Key进行加密解密。跳转的Url会在Response的Http Body中Render给用户。在使用轻量级方案的时候,最好在Key中加上时间戳,过时时间设置为3分钟。Key过时认为这个Key是非法Key,不在 Response中写入登陆成功的Cookie。 javascript
本文来源于:http://www.yaosansi.com/post/1218.html php