Passport 一方面意味著用一個帳號可以在不同服務(wù)里登錄,另一方面就是在一個服務(wù)里面登錄后可以無障礙的漫游到其他服務(wù)里面去。坦白說,目前 sohu passport 在這一點(diǎn)實(shí)現(xiàn)的很爛(不過俺的工作就是要把它做好啦,hehe)
搜狐的 SSO 需求比較麻煩,因?yàn)樗煜掠泻枚嘤蛎簊ohu.com、chinaren.com、sogou.com、focus.cn、17173.com、go2map.com,登錄用戶漫游的主要障礙也來自于此。
以前億郵的郵件系統(tǒng)在和別的系統(tǒng)整合的時(shí)候是提供一個 URL,用戶從第三方系統(tǒng)里面點(diǎn)擊這個鏈接就可以生成訪問郵件界面所需的 cookie,然后進(jìn)入郵件。這個方式的確很有效,但問題是:
1. 每個外部鏈接都必須用特殊的 URL 跳轉(zhuǎn),維護(hù)很麻煩
2. 兩個系統(tǒng)集成已經(jīng)很麻煩了,若是集成的系統(tǒng)有好幾個,彼此都需要跳轉(zhuǎn)而缺乏一個中心機(jī)制就成了噩夢
3. 根本無法處理用戶直接在地址欄輸入地址進(jìn)行訪問的情況
即使是跨域,上述的解決方法相對來說還是容易的。
A. 首先是所有登錄必須首先通過一個中央服務(wù)器進(jìn)行認(rèn)證,然后在它那里給瀏覽器種下 cookie(下面稱之為 sso cookie)
B. 當(dāng)用戶訪問另外的域名 app 的時(shí)候,瀏覽器是無法直接發(fā)送 sso cookie 給服務(wù)器認(rèn)證的。此時(shí)應(yīng)該利用 javascript,動態(tài)創(chuàng)建一個隱藏的 iframe,讓其訪問 sso
C. 這個 iframe 的請求是可以把 sso cookie 送給 sso server 的。sso server 驗(yàn)證 cookie 后,返回一個重定向頁面到 app 的某個 URL,由該 URL 設(shè)置 app cookie
D. 此時(shí)瀏覽器上可看見的頁面容器實(shí)際上也是可以和重定向回來的內(nèi)容交互的。比如可以用 js 控制發(fā)現(xiàn)重定向頁面成功返回后,就刷新整個頁面,讓它看起來和用戶登錄后訪問沒有什么區(qū)別。
下面是真正的技巧:怎樣才能在 IE 里面跨域去設(shè)置 cookie
上述技術(shù)看起來是不是很好?但它的前提是所有的登錄都 post 到 sso server 上,認(rèn)證成功后再返回 app 頁面。可我接受到的需求之一就是要支持頁面無刷新登錄。
哈!就是說本來在 chinaren.com 上提交登錄表單的 action 應(yīng)該是 passport.sohu.com 這個 sso
server。可是在 AJAX 大潮下,chinaren 計(jì)劃采用 XMLHTTPRequest 提交,這個就麻煩了,因?yàn)槭遣荒芸缬騺硖峤坏摹?/p>
那么解決方法就是跨域產(chǎn)生 cookie,即 js 發(fā)現(xiàn)口令校驗(yàn)成功后,再在 passport.sohu.com 上種上合法的 cookie.
套用上面的跨域讀 cookie 的方案似乎很簡單去推論:就是創(chuàng)建一個隱含的 iframe,讓那個 iframe 去調(diào)用
passport.sohu.com 的 URL 來產(chǎn)生 cookie。很遺憾,此方法在 Fx 下工作的很好,但是不能在 IE 上應(yīng)用。(在
IE 狀態(tài)欄上顯示 cookie 隱私警告,紅色圓底白橫杠)
我試了很多很多方法,包括創(chuàng)建 、 node,包括用 js 設(shè)置,但都一次次被 IE 無情的擋在了瀏覽器外。google 之,也沒有任何真正可用的答案,中文網(wǎng)頁要么介紹的方法是錯的,要么說無解。
最后還是在 chinaren 一哥們的幫助下,翻出了他們所使用的,以和 alumni.sohu.com 交互的方法(不知道是哪位牛人發(fā)現(xiàn)的),只需要設(shè)置 P3P HTTP Header,在隱含 iframe 里面跨域設(shè)置 cookie 就可以成功。他們所用的內(nèi)容是:
P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"
最后是我做的一個小小的演示:cookie 怎么在 vmx.cn 和 dup2.net 之間交互
1. http://qiuyingbo.test.vmx.cn/cookie.php
2. 隨便輸入什么,點(diǎn) reset cookie,就可以看到 vmx.cn 的 cookie 已經(jīng)被設(shè)上了
3. 在該頁面點(diǎn)連接到 http://www.dup2.net/vmx/cookie.html
4. 點(diǎn)"get corss-domain cookie" .. (此時(shí) js 會去創(chuàng)建一個iframe,請求 qiuyingbo.test.vmx.cn ,返回頁面把 cookie 值作為 GET 參數(shù)重定向回 dup2.net 的另外一個URL。)
5. 點(diǎn) "display corss-domain cookie" .. 就可以看到 vmx.cn 的 cookie 了
6. 在該頁面的輸入框中輸入其它的值,然后點(diǎn) "set cross-domain cookie",該行為將主動設(shè)置 vmx.cn 的 cookie
7. 點(diǎn)鏈接回到 http://qiuyingbo.test.vmx.cn/cookie.php ,就可以看到新的值了
網(wǎng)上看了別人介紹的一片文章,說使用P3P可以完成跨域COOKIE操作,感覺很COOL,不過沒有提供源代碼,我胡亂寫了一下,大家看看。
實(shí)際工作中,類似這樣的要求很多,比如說,我們有兩個域名,我們想實(shí)現(xiàn)在一個域名登錄后,能自動完成另一個域名的登錄,也就是PASSPORT的功能。
我只寫一個大概,為了測試的方便,先編輯hosts文件,加入測試域名(C:\WINDOWS\system32\drivers\etc\hosts)
127.0.0.1 www.a.com
127.0.0.1 www.b.com
首先:創(chuàng)建 a_setcookie.php 文件,內(nèi)容如下:
<?php
//header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"');
setcookie("test", $_GET['id'], time()+3600, "/", ".a.com");
?>
然后:創(chuàng)建 a_getcookie.php 文件,內(nèi)容如下:
<?php
var_dump($_COOKIE);
?>
最后:創(chuàng)建 b_setcookie.php 文件,內(nèi)容如下:
<script src="http://www.a.com/a_setcookie.php?id=www.b.com"></script>
----------------------------
三個文件創(chuàng)建完畢后,我們通過瀏覽器依次訪問:
http://www.b.com/b_setcookie.php
http://www.a.com/a_getcookie.php
我們會發(fā)現(xiàn),在訪問b.com域的時(shí)候,我們并沒有在a.com域設(shè)置上cookie值。
然后我們修改一下a_setcookie.php文件,去掉注釋符號,a_setcookie.php即為:
<?php
header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"');
setcookie("test", $_GET['id'], time()+3600, "/", ".a.com");
?>
再次通過瀏覽器依次訪問:
http://www.b.com/b_setcookie.php
http://www.a.com/a_getcookie.php
這次,你會發(fā)現(xiàn)在訪問b.com域的時(shí)候,我們設(shè)置了a.com域的cookie值。
末了補(bǔ)充一句,似乎只有IE對跨域訪問COOKIE限制比較嚴(yán)格,上述代碼在FIREFOX下測試,即使不發(fā)送P3P頭信息,也能成功。不過IE是老大啊。
參考文檔:http://www.w3.org/P3P/