雖然有一些現成的第三方解決方案比如:OpenID,Passport,SpaceCard等都還不錯,但是要麼就是收費的(passport),要麼就是有點用不習慣(比如OpenID),另外中途跳到一個界面完全不相同的第三方站點上輸入,使用者感覺也不太放心。
當然部落格園和csdn上也有不少人已經給出了相應的解決方案,但是一圈看下來,雖然思路都行得通,貌似就是沒找到不同主域名下直接利用Membership實作的例子。
那麼還是自己“造輪子”弄一個簡陋一點的方案吧,其實隻要用過Membership的朋友都知道“使用者是否已經登入”以及“使用者目前的role是什麼”等問題的判斷依據就是檢測用戶端有沒有(目前要通路)網站(所在域)的cookie票據,如果各子站都在同一個主域下,這麼問題很容易解決,隻要設定各子域cookie的domain為統一值即可,但如果各子站的主域名不同,這招就失效了(出于安全考慮,浏覽器設計時就約定不同主域的cookie不能互訪),是以問題的關鍵是:如何能讓使用者在某個域成功登入後,自動把本域下的cookie票據同步複制到其它域下!
另外還有使用者登出問題,當使用者從一個分站登出時其它分站如何登出?其實把上面的思路反過來,也能找到問題的關鍵:即一個域下的cookie票據清除後,如何能讓其它域下的cookie票據也能清除!
根本這個思路,大概整理了一個流程圖:

當然還有一些因素要考慮:比如傳遞敏感參數(比如使用者名)時應該加密;同時各分站專用于接收票據和清除票據的頁面,如何防止非法通路等等。此外,最好還要求各分站使用同一套統一的使用者名/密碼表。(當然如果各分站已經有各自的使用者資料了,也有辦法解決,比如可以建立一套新的統一帳号/密碼庫,原來各自的分站使用者表上加一個字段,映射到新庫帳号表的唯一字段)。
示例代碼:
1.解決方案結構圖
說明:
Passport:認證中心,用于統一登入和登出的類似passport站點
SiteA:站點A,其中admin需要登入才能通路(規則在web.config中配置),passport目錄下的login.aspx/loginout.aspx分别用于接收認證中心發來的票據,以及清除票據
SiteB:站點B,結構代碼完全同SiteA相同,僅為了與SiteA比較效果用
WebHelper:工具輔助類
2.技術要點:
(a)Cookie同步問題:因為cookie是基于浏覽器的,是以直接用代碼以Post或Get方式模拟通路SiteA中的/passport/login.aspx以logout.aspx時,并不能正确生成Cookie或清除Cookie,是以我采用了一個變通的辦法(隐藏的iframe)來模拟浏覽器通路這二個頁面
(b)為了盡量使用Membership的功能,少寫代碼,同時保留membership通過web.config配置目錄通路權限的風格,在passport項目中,分别針對各個站點建立A,B...等分站目錄,目的僅僅是讓ReturnUrl=/Admin/Default.aspx能自動變成類似ReturnUrl=http://www.SiteA.com/Admin/Default.aspx,以便在頁面跳轉時不需要額外處理
(3)即使是用iframe來實作跨域讀寫Cookie,預設情況下,如果使用者IE浏覽器的“隐私”級别設定為中(及中以上)時,浏覽器仍然會阻止iframe跨域設定Cookie(所謂的“同域同源”原則,即:目前浏覽器的url以及各frame/iframe裡面的頁面,如果在同一個域名,就能正常實作cookie的讀寫,否則禁止。單從這一點看,IE其實要比FF之流安全),是以需要在PassPort以及聯盟站點的IIS-->Http頭中設定相同的P3P協定值(目的是告訴IE:這一組站點互相之間是“朋友”,不要“阻擋”!),具體辦法有二種(任選一種即可):
2.1-直接寫代碼:Response.AddHeader("P3P","CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""); 把這一行加入要執行Cookie讀寫的頁面的Page_Load事件第一行(注:“CP=”後面的值可以随便設定,隻要是一個其它人不知道的string即可,相當于一個密鑰)
2.2-IIS站點屬性->HTTP頭->添加-->自定義HTTP頭為 P3P-->自定義HTTP頭值為 CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR”-->儲存
3.示例代碼說明
示例中對于參數的加密采用了Enterprise Library 4.1的加密子產品,是以需要安裝Enterprise Library才能編譯通過
利用HttpModule自動攔截機制,把原來各分站的Login.aspx/LoginOut.aspx這些都去掉了,全都在HttpModule攔截處理,同時用script 引用,代替了原來的iFrame機制
作者:菩提樹下的楊過