通常稍微規模大一些的企業,內部已經有很多的應用系統,多個系統整合首先要解決的便是“統一登錄(SSO)”問題,之前寫過一篇 利用Membership實現SSO(單點登錄) ,java環境下已經有一些開源的成熟sso項目(比如CAS),但如果覺得CAS太麻煩,想自己再造輪子重復發明一個,可以參考下面的思路:(仍然是基於Cookie的實現,只不過安全性上略有加強,cookie端存放的token標識,不再與用戶名、密碼等這些敏感信息相關)
1、組件圖

主要由3大部分組成,
1.1 SSO Client Filter 類似Asp.Net中的HttpMudule,用來攔截client webapp的所有請求,如果發現Cookie中沒有已登錄的token標識,則將請求重定向到sso 站點的login頁面;此外,它還用於接收SSO登錄成功后返回的token標識
1.2 SSO App 即SSO的主站點,提供統一的登錄認證,並將認證后的token返回給Client WebApp;以及驗證Client WebApp發送來的token是否合法。
1.3 Token Store ,用於存放所有當前登錄成功的token-user的映射關系,通常是一個key-value的hash結構,通過token(key),可找到相應的用戶(value)關鍵信息(比如:用戶名等),物理上,可用cache server/nosql db等輕量級的產品實現。
2、部署圖

3、SSO Client Filter的序列圖
verify token(A)

解釋:
當用戶要訪問Client Website中的某個頁面時,該請求首先被SSO Client Filter攔截,然后按以下流程處理:
1. 先從cookie中查找token標識
2. 如果沒找到token
3. 直接重定向到sso的login頁面,並在returnURL參數中,將請求頁面傳遞給sso
3.1 登錄成功后,生成一個token字符串,然后將token-user info的映射關系,存入token server
3.2 同時重定向到Client Website登錄前的頁面,並在url中附加一個token參數
3.2.1 Client Website收到返回的token url參數后,寫入Cookie
3.2.2 將token參數從url中去掉,重定向到登錄前的請求頁面(即:returnURL)
轉入下面的處理:
verify token(B)

1.再次從cookie中查找token
2.如果找到,則請求sso site驗證token的合法性(因為cookie中的token有可能是偽造的,或者已經失效),並帶上returnURL(以便驗證通過后,能重定向到用戶需要訪問的頁面)
3 sso收到請求的token后,到token server中驗證真偽(帶上當前請求頁面地址,做為returnUrl附帶在url參數中)
4 token server返回驗證結果
5 如果校驗失敗,則跳轉到登錄頁面,要求重新登錄(帶returnUrl)
6 如果驗證通過,返回成功標識
7 子站點拿到成功標識后,大功告成,剩下該干啥干嘛(即:正常執行頁面上的常規處理)
驗證通過后,再訪問其它頁面時,因為本地cookie中已經有token標識,所以將直接執行 verify token(B)處理。
性能分析:
從前面的分析可以看出,即使第一次認證成功后,后續的每個頁面請求都要到SSO上驗證token的真偽,這樣如果並發用戶比較多,SSO的壓力略大,可以在client website中增加二級緩存,首次驗證通過后,將token-user info的映射關系,存入Client Website自己的緩存中,這樣后續其它頁面驗證token時,直接到client website的cache中驗證即可,但這樣做的前提是client website中的token cache過期時間一定要小於sso token server中的過期時間,否則SSO Token Server中的token已經失效,但是client website中的token仍有效,就失去驗證token真偽的意義了。另外,這樣處理后,性能雖然提高了,但安全性從理論上講,將所有折扣。
安全性分析:
token的生成算法很關鍵,不要與用戶名、密碼、用戶角色等這些敏感信息相關,要保證生成的唯一字符串沒有實際業務意義(比如:可用uuid/guid之類),同時若cookie中token被竊取,為了將危害降到最低,每次token驗證成功后,最好重新生成新的token,類似手機動態密碼一樣,用過即換。
與Spring的關系:
講了半天,似乎沒看到任何Spring的影子,以上其實是SSO的通用思路,技術上適用於任何主流web技術,Spring-Security可以很容易實現SSO的用戶Form Login登錄認證,而Token Server可以用Spring-Cache來實現,至於SSO Client Filter、Client Website,Spring-MVC/Servlet Filter可以輕松搞定。
如何擴展到c/s應用
雖然SSO在很多情況下,用於整合web子系統,但只要略加改造,c/s應用其實也可以套用這個思路,比如:可以指定硬盤上某個xml文件(或windows注冊表中自己新建一個項)用來保存token(相當於瀏覽器的cookie存儲token),c/s的每個窗口統一繼承至某個父窗口,在父窗口中,每次打開時,檢測該xml中是否有token(相當於sso client filter所做的事情),如果沒有,則彈出登錄窗口,將用戶名、密碼參數,發送到sso進行認證(相當於重定向到sso的login頁面認證),認證成功后,將服務端返回的token寫入本地xml(相當於sso client filter接收token)
