1. 程式人生 > >Web應用跨域訪問及單點登入解決方案彙總

Web應用跨域訪問及單點登入解決方案彙總

做過跨越多個網站的Ajax開發的朋友都知道,如果在A網站中,我們希望使用Ajax來獲得B網站中的特定內容,如果A網站與B網站不在同一個域中,那麼就出現了跨域訪問問題。Ajax的跨域訪問問題是現有的Ajax開發人員比較常遇到的問題。
IE對於跨域訪問的處理是,彈出警告框,提醒使用者。如果使用者將該網站納入可信任網站,或者調低安全級別,那麼這個問題IE就不會在提醒你。
FireFox等其它非微軟的瀏覽器遇到跨域訪問,則解決方案統一是拒絕訪問。
有人說,IE是主流瀏覽器,只要它能正常使用就好了。此言差已,IE雖然能夠處理,但是是有前提的,要麼使用者不厭其煩地在頁面彈出警告框之後點選是(點選否就不執行該Ajax呼叫了),要麼使用者將該網站納入可信任站點。這兩種做法,在企業管理系統的應用中倒是比較常見,因為系統管理員可以以行政手段保證使用者的行為。但是對於網際網路上的網站或者門戶開發,這種做法則不行。

最近遇到了這個問題,需要在跨域訪問結束之後完成使主窗口出現一些特效,搜尋了一些資料,通過不斷嘗試以及在不同瀏覽器中進行相容性測試,找到了幾個可行的Web應用跨域訪問解決方案:
1、Web代理的方式。

即使用者訪問A網站時所產生的對B網站的跨域訪問請求均提交到A網站的指定頁面(Post頁面過去),由該頁面代替使用者頁面完成互動,從而返回合適的結果。此方案可以解決現階段所能夠想到的多數跨域訪問問題,但要求A網站提供Web代理的支援,因此A網站與B網站之間必須是緊密協作的,且每次互動過程,A網站的伺服器負擔增加,且無法代使用者儲存session狀態。


2、on-Demand方式。

MYMSN的門戶就用的這種方式,不過MYMSN中不涉及跨域訪問問題。動態控制script標記的生成,通過修改script標記的src屬性完成對跨域頁面的呼叫。此方案存在的缺陷是,script的src屬性完成該呼叫時採取的方式時get方式,如果請求時傳遞的字串過大時,可能會無法正常執行。不過此方案非常適合聚合類門戶使用。


3、iframe方式。

檢視過醒來在javaeye上的一篇關於跨域訪問的帖子,他提到自己已經用iframe的方式解決了跨域訪問問題。資料提交跟獲取,採用iframe這種方式的確可以了,但由於父視窗與子視窗之間不能互動(跨域訪問的情況下,這種互動被拒絕),因此無法完成對父視窗效果的影響。

4、使用者本地轉儲方式。

IE本身依附於windows平臺的特性為我們提供了一種基於iframe,利用記憶體來“繞行”的方案,即兩個window之間可以在客戶端通過windows剪貼簿的方式進行資料傳輸,只需要在接受資料的一方設定Interval進行輪詢,獲得結果後清除Interval即可。FF的平臺獨立性決定了它不支援剪貼簿這種方式,而以往版本的FF中存在的外掛漏洞又被fixed了,所以FF無法通過記憶體來完成暗渡陳倉。而由於檔案操作FF也沒有提供支援(無法通過Cookie跨域完成資料傳遞),致使這種技巧性的方式只能在IE中使用。


5、我自己用於解決這類問題的方式.

結合了前面幾種方式,在訪問A網站時,先請求B網站完成資料處理,再根據返回的標識來獲得所需的結果。這種方法的缺點也很明顯,B網站的負載增大了。優點,對session也實現了保持,同時A網站與B網站頁面間的互動能力增強了。最重要的一點,這種方案滿足了我的全部需要。
總結一下,以上方案中可選擇的情況下,我最推薦on-Demand方式,在不需要提交大量資料的情況下,這種方式能夠解決您的大部分問題。

==========================================================


跨平臺跨伺服器跨網站SSO(單點登入)的方案

最近在研究SSO,看到各種複雜的解決方案覺得很疑惑,自己想出了個簡單有效的方案,大家來評評有什麼問題嗎?
伺服器A:網站A
伺服器B:網站B
伺服器C:驗證網站(驗證表中有UID和KEY兩個欄位)。

1.       使用者開啟網站A的頁面http://伺服器A/a.aspx,檢測發現網站Session中沒有儲存使用者名稱UID。

2.       系統轉到驗證伺服器登入頁面,並在QUERYSTRING中附加前一個頁面的URL地址。比如http://伺服器C/login.asp?URL=http://伺服器A/a.aspx

3.       在驗證伺服器登入成功後更新驗證伺服器的Session(超時設定為足夠長,比如1天)。然後生成一個GUID值,寫入驗證表。最後,把這個GUID值和UID儲存到一個類中序列化後附加在URL中返回網站A的那個頁面。

比如http://伺服器A/a.aspx? token=sadhsagdkjasgyugd7d8yweihasdiuhagsdiuashdhaiushdi

4.       網站A的頁面讀取QUERYSTRING,然後反序列化出一個類,讀取類的UID和KEY資訊。然後,從資料庫中查詢匹配的記錄,如果找到了則表明登入成功,並把這條記錄的KEY更新成另外一個GUID(這樣就保證了即使這個URL被別人拿走再登入都不能成功)。把UID寫入伺服器A的Session中即可。

5.       使用者開啟網站B的頁面http://伺服器B/b.aspx,伺服器B上沒有當前使用者的Session資訊,自動轉向驗證伺服器檢測是否存在Session,如果找到了表明使用者已經登入過,再重複步驟3和4,如果沒有找到就轉到驗證伺服器的登入頁面。
巧妙之處在於:

l         網站伺服器和驗證伺服器都擁有一份和使用者關聯的Session,驗證到時候不需要傳任何和UID相關的資訊,因此也可以跨伺服器。正因為如此不需要使用cookie也解決了跨域名。

l         網站伺服器和驗證伺服器可以使用自己的狀態機制(不一定是Session),因此跨平臺也沒有問題。

l         用於驗證使用者的TOKEN使用GUID在每次驗證的時候都會更換,而且GUID和UID是捆綁在一起的,即使GUID碰巧對上了也不知道這個GUID對應了哪個UID。

l         通過驗證伺服器的驗證後,伺服器發回的token資料經過了序列化,使用者很難偽造。
(實在不放心還可以對這個token進行加密)
不知道大家是否理解了?
更新:經過網友提醒,我想到這個方案在登出的時候有嚴重問題,比如A網站登出了,我們不能通知其它網站該使用者已經登出,它再切換到其它網站又是登入狀態(因為Session沒有過期),不過我也想到了一個解決方案。就是所有的網站都有一個專門的頁面或者服務,根據傳過來的令牌來清空這個當前使用者的Session。登出以後把所有網站的Session都清空,如果網站不是很多的情況下還好,網站一多登出就會很慢了!
更新:現在看來已經沒有什麼問題了,到時候放出完整DEMO!
更新:有網友不理解為什麼關閉瀏覽器所有網站退出登入?因為Session是和使用者瀏覽器例項關聯的,而我們所有網站都使用Session,因此關閉了瀏覽器所有網站都退出了。這個和退出登入按鈕不一樣,退出登入按鈕需要發通知讓所有網站清除Session。
更新:我們現在把這個框架的登入放到了各個網站中,保證登入和退出在登入伺服器Down的情況下也能進行,只是不能進行跨站登入罷了。登入伺服器Down還能實現本站登入和退出。過幾天放出完整原始碼!


==========================================================

單點登陸問題-實現單點登陸的幾種方法
1 可以實現單點登陸的幾種方法

(1)基於domain的方案
這種方案是我公司目前使用的一種方案,原理:應用A在a.domain.com,B在b.domain.com,如果設cookie的時候,設domain為domain.com,那在A、B上都可以訪問到這個cookie了。(cookie的domain、path、port、version、secure相同)。
該方案特點:
1、不能夠跨域
2、在網路中傳送使用者名稱和密碼
3、只支援J2EE應用
(2)基於gateway的方案
實際部署的時候,對所有應用的請求,都要通過一個gateway轉發一下,比如用一個L4的交換機頂在前面。
(3)基於tooken傳遞的方案
主要是以耶魯大學的CAS專案為基礎。
注意:你自己的應用看不到使用者的密碼。由CAS執行授權,只有CAS能看到使用者的密碼。這樣增加發安全性,因為使用者名稱和密碼不會通過網路在應用間傳播。
下面是使用CAS整合的單點登入用例
用例一:
一臺認證伺服器(假定為AUTH),有兩個應用A、B,分別部署在不同的伺服器上。
1) 使用者訪問A,A應用無法找到使用者的身份資訊,使用redirect方法將使用者引導至http://Auth/login?service=http://A/path。
2) AUTH 顯示登入介面,使用者輸入登入資訊,認證通過。
3) AUTH產生一個cookie(這個cookie只有AUTH上才能讀到),使用redirect方法將使用者引導回http://A/path?token=xxxxx(在有的解決方案上,這個token是通過一定編碼演算法的Account資訊)
4) A讀取token=xxxx的資訊,獲取使用者身份。
5) 使用者訪問B。B未找到使用者的身份資訊,redirect至http://AUTH/login?service=http://B/path
6) AUTH讀cookie獲取使用者身份,然後redirect回http://B/path?token=xxxx
7) B讀取token=xxxx資訊,獲得使用者身份資訊
用例二:
使用者訪問一個Web應用的過程。

具體的參看 http://www.9ta8.com/YaleCASServer.mht
(4)USBKey登入
這個方案是北京點聚資訊科技有限公司提供的,我也向他們的技術諮詢了相關的問題。他們的實現方式基本上是這樣的:每個使用該系統的使用者都有一個USBKey證書,在登陸系統的時候把這個證書插在計算機上。每一個網站都要通過這個證書去認證。
這樣每個登入使用者只需插上USBKey即可進入任意受信任系統,當然訪問USBKey首先需要密碼校驗。
2  個人認為單點登陸實際上就兩種方案
首先確認要使用單點登陸,必須有一個核心,那就是不管使用者走到那個平臺,他必須要帶著他的通行證,單點登陸最關鍵的問題是使用者怎麼取得、儲存、使用這個通行證的問題。  使用者要取得他的通行證其實不外乎以下兩種方案:
第一種:所有的業務平臺整合在一個Portal上,去每一個平臺的時候都要帶著他的“通行證”,這就是所謂的“Tooken傳遞方案”;
第二種:使用硬體卡,就是上面所說的“USBKey登陸”;
3  單點登陸的幾個案例
(1)微軟一篇關於單點登陸的文章,他的實現是使用第一種方案。
原文:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/singlesignon.asp

(2)SharePoint Portal Server 2003 中的單一登入

http://www.microsoft.com/china/technet/prodtechnol/sppt/reskit/c2661881x.mspx

(3)《WebCast SharePoint Portal Server 2003 Single Sign On 管理及開發》已提供下載

http://www.msotec.net/Forums/ShowThread.aspx?PostID=415

4  單點登陸的參考方法
伺服器端可控JS跨域訪問解決方法

http://bbs.ad0.cn/viewthread.php?tid=302&extra=page%3D1

SSO – Single Sign-On Enterprise Security for Web Applications

http://bbs.ad0.cn/viewthread.php?tid=304&extra=page%3D1

單點登入的簡單實現

http://bbs.ad0.cn/viewthread.php?tid=305&extra=page%3D1

PHP實現WebServices和跨域自動登陸

http://bbs.ad0.cn/viewthread.php?tid=307&extra=page%3D1

Passport跨域認證解決方法

http://bbs.ad0.cn/viewthread.php?tid=309&extra=page%3D1

Web應用跨域訪問解決方案

http://bbs.ad0.cn/viewthread.php?tid=310&extra=page%3D1

Flex或Flash的跨域訪問解決方案

http://bbs.ad0.cn/viewthread.php?tid=313&extra=page%3D1

跨域訪問新方案-PHPRPC

http://bbs.ad0.cn/viewthread.php?tid=315&extra=page%3D1

==========================================================
PHP使用P3P完成跨域COOKIE操作[轉載]
實際工作中,類似這樣的要求很多,比如說,我們有兩個域名,我們想實現在一個域名登入後,能自動完成另一個域名的登入,也就是PASSPORT的功能。
為了測試的方便,先編輯hosts檔案,加入測試域名(C:\WINDOWS\system32\drivers\etc\hosts)
127.0.0.1       www.a.com
127.0.0.1       www.b.com
首先:建立 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”);
?>
然後:建立 a_getcookie.php 檔案,內容如下:
<?php
var_dump($_COOKIE);
?>
最後:建立 b_setcookie.php 檔案,內容如下:
<script src=”http://www.a.com/a_setcookie.php?id=www.b.com”></script>
----------------------------
三個檔案建立完畢後,我們通過瀏覽器依次訪問:

http://www.b.com/b_setcookie.php

http://www.a.com/a_getcookie.php

我們會發現,在訪問b.com域的時候,我們並沒有在a.com域設定上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

這次,你會發現在訪問b.com域的時候,我們設定了a.com域的cookie值。

==========================================================
跨域(cross-domain)訪問 cookie (讀取和設定)[轉,儲存][轉載]

Passport 一方面意味著用一個帳號可以在不同服務裡登入,另一方面就是在一個服務裡面登入後可以無障礙的漫遊到其他服務裡面去。坦白說,目前 sohu passport 在這一點實現的很爛(不過俺的工作就是要把它做好啦,hehe)
搜狐的 SSO 需求比較麻煩,因為它旗下有好多域名:sohu.com、chinaren.com、sogou.com、focus.cn、17173.com、go2map.com,登入使用者漫遊的主要障礙也來自於此。
以前億郵的郵件系統在和別的系統整合的時候是提供一個 URL,使用者從第三方系統裡面點選這個連結就可以生成訪問郵件介面所需的 cookie,然後進入郵件。這個方式的確很有效,但問題是:
1. 每個外部連結都必須用特殊的 URL 跳轉,維護很麻煩
2. 兩個系統整合已經很麻煩了,若是整合的系統有好幾個,彼此都需要跳轉而缺乏一箇中心機制就成了噩夢
3. 根本無法處理使用者直接在位址列輸入地址進行訪問的情況
即使是跨域,上述的解決方法相對來說還是容易的。
A. 首先是所有登入必須首先通過一箇中央伺服器進行認證,然後在它那裡給瀏覽器種下 cookie(下面稱之為 sso cookie)
B. 當用戶訪問另外的域名 app 的時候,瀏覽器是無法直接傳送 sso cookie 給伺服器認證的。此時應該利用 ,動態建立一個隱藏的 ,讓其訪問 sso
C. 這個 i 的請求是可以把 sso cookie 送給 sso server 的。sso server 驗證 cookie 後,返回一個重定向頁面到 app 的某個 URL,由該 URL 設定 app cookie
D. 此時瀏覽器上可看見的頁面容器實際上也是可以和重定向回來的內容互動的。比如可以用 js 控制發現重定向頁面成功返回後,就重新整理整個頁面,讓它看起來和使用者登入後訪問沒有什麼區別。
下面是真正的技巧:怎樣才能在 IE 裡面跨域去設定 cookie
上述技術看起來是不是很好?但它的前提是所有的登入都 post 到 sso server 上,認證成功後再返回 app 頁面。可我接受到的需求之一就是要支援頁面無重新整理登入。
哈!就是說本來在 chinaren.com 上提交登入表單的 action 應該是 passport.sohu.com 這個 sso server。可是在 AJAX 大潮下,chinaren 計劃採用 HTTPRequest 提交,這個就麻煩了,因為是不能跨域來提交的。
那麼解決方法就是跨域產生 cookie,即 js 發現口令校驗成功後,再在 passport.sohu.com 上種上合法的 cookie.
套用上面的跨域讀 cookie 的方案似乎很簡單去推論:就是建立一個隱含的 iframe,讓那個 iframe 去呼叫 passport.sohu.com 的 URL 來產生 cookie。很遺憾,此方法在 Fx 下工作的很好,但是不能在 IE 上應用。(在 IE 狀態列上顯示 cookie 隱私警告,紅色圓底白橫槓)
我試了很多很多方法,包括建立 、 node,包括用 js 設定,但都一次次被 IE 無情的擋在了瀏覽器外。google 之,也沒有任何真正可用的答案,中文網頁要麼介紹的方法是錯的,要麼說無解。
最後還是在 chinaren 一哥們的幫助下,翻出了他們所使用的,以和 alumni.sohu.com 互動的方法(不知道是哪位牛人發現的),只需要設定 P3P HTTP Header,在隱含 iframe 裡面跨域設定 cookie 就可以成功。他們所用的內容是:
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. 隨便輸入什麼,點 reset cookie,就可以看到 vmx.cn 的 cookie 已經被設上了
3. 在該頁面點連線到 http://www.dup2.net/vmx/cookie.html
4. 點’get corss-domain cookie’ .. (此時 js 會去建立一個iframe,請求 qiuyingbo.test.vmx.cn ,返回頁面把 cookie 值作為 GET 引數重定向回 dup2.net 的另外一個URL。)
5. 點 ‘display corss-domain cookie’ .. 就可以看到 vmx.cn 的 cookie 了
6. 在該頁面的輸入框中輸入其它的值,然後點 ’set cross-domain cookie’,該行為將主動設定 vmx.cn 的 cookie
7. 點連結回到 http://qiuyingbo.test.vmx.cn/cookie.php ,就可以看到新的值了
通過設定P3P頭來實現跨域訪問COOKIE

==========================================================

單點登入的簡單實現
SSO 單點登入的簡單實現 實現入口網站單點登入
在門戶專案中,經常會遇到如何實現單點登入的問題,下面就本人的經驗做個總結。歡迎大家進行補充討論。
單點登入的具體實現有很多種選擇,包括:
採用專門的SSO商業軟體: 主要有:Netgrity的Siteminder,已經被CA收購。Novell 公司的iChain。RSA公司的ClearTrust等。
採用門戶產品供應商自己的SSO產品,如:BEA的WLES,IBM 的Tivoli Access Manager,Sun 公司的identity Server,Oracle公司的OID等。
這些商業軟體一般適用於客戶對SSO的需求很高,並且企業內部採用COTS軟體如:Domino,SAP,Sieble的系統比較多的情況下采用。並結合身份管理。統一認證等專案採用。採用這些軟體一般都要對要整合的系統做些改造,如在要整合的系統上安裝AGENT。現在一般只提供常見軟體如:Domino,SAP,Sieble,常見應用伺服器:weblogic,websphere等的AGENT。要先統一這些系統的認證。一般採用LDAP或資料庫。然後才能實現SSO。比較麻煩。
另外,如果不想掏銀子,也有OPEN SOURCE的SSO軟體可選:主要有:http://www.josso.org/ https://opensso.dev.Java.net/ http://www.sourceid.org 等。具體怎麼樣就不清楚了。

==========================================================

在PHP中實現單點登入(Single Sign On)的一種簡單方法
單點登入是大容量系統必備的功能,市面上有幾款昂貴的商業系統,若不是財大氣粗,恐怕用不起。
怎麼樣才能簡單、經濟的實現這個功能?我們在這裡探討一種可行的方案。
當前開發Web應用中,Apache + PHP + MySQL是中小型企業降低成本的必選架構,這裡我們來實現PHP的單點登入,讓這種經濟性的架構能夠擴充套件到的群集伺服器層面。
我們的設想是將PHP的Session資料集中儲存,這樣對於不同伺服器中執行的PHP來說,只有一個共有的Session資料庫,那麼使用者在伺服器A登入所生成的Session資料在伺服器B、C、D等伺服器都可以共享,就可以免除多次登入。但由於PHP的Session是需要Cookie的,而Cookie又是與域名相關的,所以採用這個方案的各個伺服器需要有相同的域名(至少是相同的二級域名),比如:
1、所有伺服器的域名都是www.whybsd.com,這個東東DNS輪詢就可以實現;這個時候,在PHP中將Cookie域名設定為www.whybsd.com即可;
2、所有伺服器的域名都是以.whybsd.com結尾的三級域名,比如a.whybsd.com,b.whybsd.com等等,這個時候,在PHP中將Cookie域名設定為.whybsd.com就可以共享Cookie了。
解決了先決條件,我們現在來看看PHP的Session儲存方法,在PHP手冊說明中,有一個叫session_set_save_handler()的函式,這個函式是用來註冊使用者自定義的Session資料儲存介面的。
以下是PHP手冊自帶的示例:
程式碼:

<?php
function open($save_path, $session_name) {
global $sess_save_path, $sess_session_name;

$sess_save_path = $save_path;
$sess_session_name = $session_name;
return(true);
}
function close() {
return(true);
}
function read($id) {
global $sess_save_path, $sess_session_name;
$sess_file = “$sess_save_path/sess_$id”;
if ($fp = @fopen($sess_file, “r”)) {
$sess_data = fread($fp, filesize($sess_file));
return($sess_data);
} else {
return(“”); // Must return “” here.
}
}
function write($id, $sess_data) {
global $sess_save_path, $sess_session_name;
$sess_file = “$sess_save_path/sess_$id”;
if ($fp = @fopen($sess_file, “w”)) {
return(fwrite($fp, $sess_data));
} else {
return(false);
}
}
function destroy($id) {
global $sess_save_path, $sess_session_name;

$sess_file = “$sess_save_path/sess_$id”;
return(@unlink($sess_file));
}
/*********************************************
* WARNING – You will need to implement some *
* sort of garbage collection routine here.  *
*********************************************/
function gc($maxlifetime) {
return true;
}
session_set_save_handler(“open”, “close”, “read”, “write”, “destroy”, “gc”);
session_start();
// proceed to use sessions normally
?>

按照這種思路,我們只要編寫自己的處理函式並進行相應的註冊,就可以實現PHP Session資料的自定義儲存了。
具體實現可以開動你的思路,比如可以使用NFS將Session資料儲存到統一的網路裝置中,也可以將Session資料儲存到一個數據庫中,讓所有伺服器連線這個共享資料庫(比如MySQL)就可以了。
嗯,比較簡單,而且經濟。
更多考慮:
1、效能需要考量,特別是伺服器數(引起資源佔用)和使用者量(引起Session量)非常巨大的時候。
==========================================================
PHP實現WebServices和跨域自動登陸
1、webservices的php實現
主要是基於nusoap這個庫來實現的,其不但可以實現server功能還可以實現client功能,支援end point和WSDL兩種方式;連soap協議的xml訊息都是自己解析的,所以完全可以脫離其他php庫支援;優點之一啊;可惜,可能有效能上的憂慮。
2、session跨域自動登陸
瞭解http協議特性的人都知道(參考RFC),服務端session只能是通過cookie或者get、post方法傳遞的unique id來實現的;因此欺騙服務端session的行為理論上是很容易實現的,只要你知道那個unique id及傳遞的方式;而在某個session建立之後,只要傳遞給其該唯一標示,其都是可以被認可為會話客戶的;因此,在獲得會話id的前提下任何跨域session訪問都是可能的。通過get、post方式的id容易拿到和建立,而通過cookie傳遞的就必須突破瀏覽器的跨域cookie建立限制,當然如果需要實現跨域session建立的是可控制的服務端,那問題就迎刃而解了(不過該條件下的解決方案有多種,例如互連星空就使用的URL轉向方法)。PHP實現WebServices和跨域自動登陸具體例子就不詳述了。
==========================================================
Passport跨域認證解決方法
非常簡單的Passport跨域認證解決方法:
1、架設一個PASSPORT伺服器(該伺服器命名為A)。所有的使用者驗證都通過此伺服器驗證,其他伺服器對使用者資訊的獲取,使用者的身份確認,都要通過這個伺服器來實現。
2、在應用伺服器(該伺服器命名為B)的所有需要驗證的地方判斷使用者資訊是否已經驗證,如果沒有驗證,則通過 IFRAME 在用頁面放一個A伺服器的驗證頁面,並傳遞一個A可以識別的標記引數,告訴A伺服器是B伺服器需要驗證當前使用者。
3、A伺服器獲得B伺服器的頁面請求後,首先檢查當前使用者是否登陸,如果沒有登陸,則停止驗證,或者反饋一個尚未登陸的頁面。
4、如果A使用者收到B伺服器的也面請求後,發現當前使用者已經登陸,則生成一個隨機的長的字串並在記錄下該字串、生成時間、對應的使用者記錄、B伺服器的標記。然後通過自動跳轉技術,訪問B伺服器上的一個使用者資訊驗證頁面,同時傳遞所生成的長字串。(該頁面由A從自身記錄中獲取,由事先錄入);
5、B伺服器的驗證頁面收到到所傳遞的長字串後,在伺服器端訪問A伺服器的伺服器端資訊確認頁面,同時傳遞所收到的長字串以及伺服器標識。
6、A伺服器的伺服器端資訊確認頁面收到資訊後,通過字串與發出請求的伺服器來驗證資訊的正確性:
(1)首先判斷伺服器IP是否屬於該PASSPORT的服務伺服器列表;
(2)通過字串查詢記錄中是否有該字串;
(3)通過請求伺服器的IP與保留的伺服器標記核對,看是否請求的IP地址是當前記錄的伺服器的;
(4)判斷字串的生成時間與當前時間比較,是否超時,超時的設定,在A伺服器上設定;
(5)如果都核對無誤,則返回對應的使用者資訊,否則反饋錯誤資訊;
7、B伺服器受到A伺服器的確認資訊後,根據確認資訊的內容,判斷使用者是否登陸成功,如果登陸成功,則給當前使用者分配SESSION。如果不成功,則返回空白或者重複剛才的程序,重新驗證(重新驗證需要記錄次數,當次數超過一定量,則無條件停止驗證,避免死迴圈)

Passport跨域認證解決方法 參考:
伺服器端可控JS跨域訪問解決方法

http://bbs.ad0.cn/viewthread.php?tid=302&extra=page%3D1

SSO – Single Sign-On Enterprise Security for Web Applications

http://bbs.ad0.cn/viewthread.php?tid=304&extra=page%3D1

單點登入的簡單實現

http://bbs.ad0.cn/viewthread.php?tid=305&extra=page%3D1

PHP實現WebServices和跨域自動登陸

http://bbs.ad0.cn/viewthread.php?tid=307&extra=page%3D1

Passport跨域認證解決方法

http://bbs.ad0.cn/viewthread.php?tid=309&extra=page%3D1

Web應用跨域訪問解決方案

http://bbs.ad0.cn/viewthread.php?tid=310&extra=page%3D1

Flex或Flash的跨域訪問解決方案

http://bbs.ad0.cn/viewthread.php?tid=313&extra=page%3D1

跨域訪問新方案-PHPRPC

http://bbs.ad0.cn/viewthread.php?tid=315&extra=page%3D1

SSO-單點登入完全解決方案
—-最全的SSO解決方案,
AJAX跨域問題,IFrame跨域問題,Cookies跨域,session跨域問題,Js跨域問題,等常見跨域問題均有提及
Ajax跨域工具: Modello.ajax
—跨瀏覽器、跨域的Ajax工具

跨域訪問新解決方案(跨域呼叫新方案)- PHPRPC
PHPRPC – perfect high performance remote procedure call
PHPRPC 是一個輕型的、安全的、跨網際的、跨語言的、跨平臺的、跨環境的、跨域的、支援複雜物件傳輸的、支援引用引數傳遞的、支援內容輸出重定向的、支援分級錯誤處理的、支援會話的、面向服務的高效能遠端過程呼叫協議。
目前該協議的最新版本為 3.0。該版本目前已有以下幾種語言的實現:

ASP:提供 JScript 和 VBScript 兩種語言的支援。
ActionScript:提供 ActionScript 2.0 和 ActionScript 3.0 兩個版本的支援。
Java:支援 JDK 1.4 以上的所有版本,它還支援 Google Android 開發包。
JavaScript:提供兩個版本的實現,一個使用純 Javascript 實現,另一個需要呼叫一個 swf 檔案,兩個版本都支援跨域的遠端過程呼叫,但是使用 swf 的版本不限制引數長度,並且有更好的安全控制機制。這兩個版本已經通過完整測試的瀏覽器包括 IE 5+,Netscape 7+,Firefox,Mozilla,Opera,Safari,Epiphany,Camino 與 Konqueror。並且純 JavaScript 版本還通過了 Pocket IE、Opera Mini、Opera Mobile、iPhone、Android 等手持裝置瀏覽器的測試。
.NET:支援 .NET 框架下所有的語言(如 C#、VB.NET、VC.NET、Delphi.NET 等),並且支援目前所有版本的 .NET Framework 和 .NET Compact Framework,當然它也支援 Mono。
PHP:支援 PHP4 與 PHP5,同樣支援正處於開發階段的 PHP6。
Perl:目前該版本尚不成熟,有待完善。
其中 ASP、.NET、Java 和 PHP 版本除了提供客戶端實現外,還提供了 伺服器端實現。

PHPRPC 3.0下載:http://www.phprpc.org/download/phprpc_3.0.zip

PHPRPC 3.0各版本: http://www.phprpc.org/zh_CN/download/
搜尋《跨域訪問新方案-PHPRPC》相關主題: 遠端呼叫 跨域呼叫 解決方案 跨域訪問 PHPRPC PHPRPC 方案 訪問

==========================================================
php sso單點登入實現方案

http://www.dayanmei.com/blog.php/ID_1021.htm

由於已經現成有多個不同的應用,各個應用有自己的user資料,我擬定的做法是
1.    共建一個user表,通過應用繫結使用者跟user表的關係
拷貝所有現有的使用者和密碼到新表,並驗證密碼的驗證方式函式
2.    一個配置檔案中設定各個應用與user表之間傳輸加密解密協議
3.    當一個使用者登入時他首先攜帶當前的url地址或者是需要返回的url地址和通過加密協議加密後的字串提交到驗證伺服器,驗證後返回加密後的狀態和票據,其中可能包含過期時間產生時間等,
如果成功,則同樣的票據通過javascript src的方式提交給其他的應用,產生cookie或者session
4.    php sso單點登入實現方案檔案示例
config.inc.php 公用金鑰和驗證函式庫
ps-mm.cn域名下檔案
a_setcookie.php (產生cookie 登入當前應用)
printcookie.php (測試列印cookie)
dayanmei.com 域名下檔案
驗證伺服器檔案
b_setcookie.php
內容:
config.inc.php
<?php
$key = ‘123456789′;
function authcode($string, $operation, $key = ”) {
$key = md5($key ? $key : $GLOBALS['auth_key']);
$key_length = strlen($key);
$string = $operation == ‘DECODE’ ? base64_decode($string) : substr(md5($string.$key), 0, 8).$string;
$string_length = strlen($string);
$rndkey = $box = array();
$result = ”;
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($key[$i % $key_length]);
$box[$i] = $i;
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if($operation == ‘DECODE’) {
if(substr($result, 0, 8) == substr(md5(substr($result, 8).$key), 0, 8)) {
return substr($result, 8);
} else {
return ”;
}
} else {
return str_replace(‘=’, ”, base64_encode($result));
}
}
//posts transaction data using libCurl
function libCurlPost($url,$data)  {
//build post string
foreach($data as $i=>$v) {
$postdata.= $i . “=” . urlencode($v) . “&”;
}
$postdata.=”cmd=_notify-validate”;
$ch=curl_init();
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POST,1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$postdata);
//Start ob to prevent curl_exec from displaying stuff.
ob_start();
curl_exec($ch);
//Get contents of output buffer
//$info=ob_get_contents();
curl_close($ch);
//End ob and erase contents.
ob_end_clean();
//return $info;
}
//posts transaction data using fsockopen.
function fsockPost($url,$data) {
//Parse url
$web=parse_url($url);
//build post string
foreach($data as $i=>$v) {
$postdata.= $i . “=” . urlencode($v) . “&”;
}
$postdata.=”cmd=_notify-validate”;
//Set the port number
if($web[scheme] == “https”) { $web[port]=”443″;  $ssl=”ssl://”; } else { $web[port]=”80″; }
//Create paypal connection
[email protected]($ssl . $web[host],$web[port],$errnum,$errstr,30);
//Error checking
if(!$fp) {
//echo “$errnum: $errstr”;
}else {
fputs($fp, “POST $web[path] HTTP/1.1\r\n”);
fputs($fp, “Host: $web[host]\r\n”);
fputs($fp, “Content-type: application/x-www-form-urlencoded\r\n”);
fputs($fp, “Content-length: “.strlen($postdata).”\r\n”);
fputs($fp, “Connection: close\r\n\r\n”);
fputs($fp, $postdata . “\r\n\r\n”);
//loop through the response from the server
while(!feof($fp)) {
$info[][email protected]($fp, 1024);
}
//close fp – we are done with it
fclose($fp);
//break up results into a string
$info=implode(“,”,$info);
}
return $info;
}
?>
Pirntcookie.php
<?php
print $_COOKIE['test'];
?>
A_setcookie.php
<?php
header(‘P3P: CP=”CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV”‘);
include(‘config.inc.php’);
$string = explode(“\n”,authcode($_GET['string'],’DECODE’,$key));
setcookie(“test”, $string[1], time()+3600, “/”, “.ps-mm.cn”);
?>
B_setcookie.php
<script src=”http://www.ps-mm.cn/a_setcookie.php?string=f20Bq5QGXqSRKlpwuTfB”></script>