背景
随着互联网技术的发展,各式各样的互联网公司在崛起,也在给人们的生活提供着各种方便。也伴随着公司的不断壮大,业务在不停的扩展,同一公司下会有很多不同的产品,不同的产品可能使用了不同的域名,但是他们可能会使用公司统一的帐号服务,所以简历统一的帐号服务体系就成为了必然。比如说:淘宝(www.taobao.com)和天猫(www.tmall.com)它们使用了相同的帐号,在不同的产品和域名下进行了帐号的统一管理。
目的
基于这样一个大的背景,今天想要讨论一下如何实现一个统一的帐号服务?并且如何减少这种服务带来的问题?
实现细节
关于怎么实现,我们很简单就想到了使用单点登录(http://www.blogjava.net/Jack2007/archive/2008/04/10/191795.html)实现。它的基本原理就是:在一个域名下进行认证之后,在其他信任的域名列表不需要在进行登录认证,用一张图片说明如下:
而我要讲的是如何实现单点登录,算是一个实践例子。
我们知道如何证明一个用户在该域名下是否是登录状态,必须存在一个标识进行标注。在web应用中,浏览器的cookie就担任了这么一个角色,可以很方便的记录用户的登录状态或者用户其他信息(但是处于安全的考虑,一般用户信息不建议使用cookie进行记录,除非是不重要的信息)。目前基本上所有的web应用的帐号体系都是通过cookie记录用户状态,这也进一步佐证了为什么禁用了浏览器的cookie好多登录都会失效(这个大家可以进行实验,禁用浏览器cookie后,对想要测试的网站进行登录即可)。
那么怎么让不同的域名同样具备相同的登录状态的?首先可以看一下有哪些情况:假设我们公司现在存在四个域名,分别是:www.a.com www.b.com www.c.com user.a.com。其实这就是两种情况,第一种是:不同域名;第二种是不同子域。不同子域有一种简单的实现方式就是直接设置不同子域共用根域的cookie信息即可,对于不同域名的情况,只要通过某种方式将cookie设置到它们域名下即可,我这里使用的方式是将不同的域名cname(http://baike.so.com/doc/6836406.html)到主域名,然后向不同的域名设置cookie。
下面介绍上述两种情况的具体实现:www.a.com和user.a.com可以设置cookie时,加上domain参数,如:domain: ‘a.com‘,这样主域的登录状态被设置成功时,子域就可以访问这个状态了;www.a.com、www.b.com 、www.c.com可以启用一个公用的服务域名,passport.a.com passport.b.com passport.c.com分别向a.com、b.com、c.com设置cookie,这样就转换成了本域的情况了。以a.com为主域,passport.b.com和passport.c.com可以cname到passport.a.com即可。
上面说到的就完成了不同域名设置登录状态的情况,这只是完成了第一步,相当于上图说的ticket,然后就是拿上这个ticket进行验证 。
后续可以做的
安全问题:
上面的这种做法存在一些安全问题,上面讲到不同子域可以共享根域的cookie,这样就会存在cookie泄漏的问题,解决方案就是要控制a.com下的子域名都要受自己控制不能被滥用;其次需要防止的网站被xss攻击,攻击之后攻击者获取ticket,然后就可以验证了。这种方式可以采用双因子验证,其中一个为httpOnly这样的话,只有部署了sdk才能验证成功,还可以对reffer进行设置,采用白名单机制也能有效的进行防御;还可以通过https、post请求、验证码、频度限制进行控制。
易用性
现在提供的帐号登录、注册相关,都普遍采用弹层的形式,这样对用户来说提供了一个简单、易操作的入口,不需要进行跳转提升了用户的体验。这样就需要解决的就是跨域设置cookie的问题,常用的就是jsonp的形式,这种情况无法进行post请求,建议使用iframe+post形式。特别的密码需要直接加密后进行传递,这样对用户隐私也是一种保护。
以上是自己在实践中的一些想法,欢迎讨论、拍砖~
参考资料:
http://www.blogjava.net/Jack2007/archive/2008/04/10/191795.html
http://shaoshuai.me/tech/2014/08/16/cookie-theft-and-session-hijacking.html
如何建立统一帐号服务