不同系统间的账户登录-Cookie跨域

作者 Gavin 日期 2015-09-15
不同系统间的账户登录-Cookie跨域

这两天在做:让两个系统间的帐号同步,其中涉及到跨域登录.

背景是这样的:现在有两个系统SystemA和SystemB,要求在SystemA里可以注册SystemB的帐号,同时注册SystemB的时候需要依赖一个新的SystemA的帐号,并且要求在登录SystemB的时候同时登录SystemA的新帐号,并且在同一个浏览器内可以同时登录SystemA的初始帐号SA,SystemB的帐号SB和SystemA的新帐号SAN.

系统SystemA和SystemB都是采用Cookie记录登录操作的. 因此需要同时有SA, SB, SAN三者的Cookie.

解决方案是:使用三个域名(abc.com, sb.abc.com, newsa.abc.com),其中SA访问abc.com进行登录, SAN访问newsa.abc.com进行登录, SB访问sb.abc.com进行登录. 其中abc.comnewsa.abc.com都指向SystemA, sb.abc.com指向SystemB. 这样SA登录的时候使用域abc.com的Cookie, SAN登录的时候使用newsa.abc.com的Cookie, SB登录的时候使用sb.abc.com的Cookie.

  • 跨域登录:其实很简单,首先使用SA登录abc.com,这时候已经种植了abc.com的Cookie, 然后用SB登录SystemB成功后种植了sb.abc.com的Cookie, 登录SystemB的时候动态生成一个script,该script的src指向newsa.abc.com的一个URL,该URL负责种植域newsa.abc.com下的Cookie(也就是采用动态载入异域的script解决跨域).

sb.abc.com的登录页面ajax验证登录成功后执行下面的代码,动态引入newsa.abc.com的一个URL作为dom-script.

你可能会问为什么不在sb.abc.com直接种植newsa.abc.com下的Cookie呢?

因为种不了,这属于跨域了. sb.abc.com可以种植sb.abc.com和abc.com下的Cookie, 无法在同级别的二级域名下种植Cookie.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function loadScript(url, callback, callbackData){
var script = document.createElement("script")
script.type = "text/javascript";
if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" ||
script.readyState == "complete"){
script.onreadystatechange = null;
callback(callbackData);
}
};
} else { //Others: Firefox, Safari, Chrome, and Opera
script.onload = function(){
callback(callbackData);
};
}
script.src = url;
document.body.appendChild(script);
}
loadScript('http://newsa.abc.com/project/setcookie', callback, callbackData) ;

嗯,还支持简单的回调 ~

  • 父域和子域Cookie的发送优先级

没错,通过上面的异步引入newsa.abc.com一个种植Cookie的URL我们可以成功种植Cookie.

But, 当我们访问newsa.abc.com的时候发现浏览器在Header里发送的不是 newsa.abc.com的Cookie, 而是abc.com的Cookie. 即当父域和子域的Cookie同时存在时访问子域的URL,浏览器会优先发送父域的Cookie.

我们翻阅下种植Cookie的方法:

1
bool setcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]]]] )

path 就是我们解决问题的关键,由于项目正好不是在域名下的'/'根目录,所以对于子域的Cookie, 我们种植到项目目录下,父域的Cookie还是种植到'/'根目录, 假设项目目录为:/project,当访问abc.com/project下的URI时,发送的是abc.com的Cookie, 访问newsa.abc.com/project的URI时,发送的是newsa.abc.com的Cookie(因为我们设置了newsa.abc.com的Cookie的path,所以优先发送. )

当然我们完全可以将newsa.abc.com替换成def.com,这样就不涉及子域,父域的Cookie共享问题了,但是我们有自己的业务考虑,使用newsa.abc.com对用户来说更能体现我们业务的紧密型.


总结下Cookie的跨域共享:

  1. 在可读取的path下子域可以共享父域的Cookie,同时如果二者都存在,优先使用匹配当前path的Cookie.
  2. 不同的子域之间不能种植Cookie.
  3. 子域可以种植父域的Cookie.
  4. 父域不可以种植子域的Cookie.
  5. 父域不可以共享子域的Cookie.