在上一篇文章git
如何設計一個單點登陸系統(2)?github
中主要講解了可跨域SSO系統服務端,客戶端在登陸,登出過程當中分別應該承擔的職責,本文將重點聊一下具體技術實現,源碼地址: https://github.com/zhoudapeng/zssoredis
首先聊服務端的實現,畢竟服務端是整個單點登陸系統的大腦spring
提供登陸頁,這個是登陸的基礎,全部的接入方在發現當前用戶未登陸的狀況下都會重定向到sso服務端的登陸頁,服務端的邏輯以下:跨域
這裏服務端須要作個判斷:cookie
若是當前登陸存在.sso.com域下的有效cookie,則證實此用戶以前在其餘業務系統登陸過,此時無需再讓用戶登陸,只須要綁定token與此係統名的關係,而後重定向到此係統的回調接口(接入方須要在此回調接口中驗證token,建立本地會話)分佈式
不存在.sso.com域下的有效cookie,證實此用戶未登陸過,須要跳轉到登陸頁,讓用戶登陸,爲了用戶登陸後能直接進入以前的頁面,這裏重定向的過程當中須要帶上redirectUrl 這個參數post
2.提供登陸接口,用戶在登陸頁輸入帳號密碼後會經過form表單已post的形式提交到此接口優化
若是帳號密碼不對,則再次跳轉到登陸頁
帳號密碼匹配,則須要建立token,綁定token與系統名的關係,寫全局cookie,而後重定向到接入方的回調地址
3.提供驗證token接口
token不存在,返回驗證失敗
token存在,則取出token的有效截止日期,並綁定token與系統名的關係
4.提供登出接口
登出時,須要根據token查到全部綁定過的系統名,而後調用各個系統的登出接口一一登出。
以上是服務端須要提供的4個接口,下面咱們再將一下客戶端的實現
在第一篇文章中講過,一個好的sso系統必需要讓接入方接入簡單,因此本人借鑑了spring auto-driven的思想,也提供了對應的命名空間,並抽象出了UrlHelper,UserStore,ZssoClient,ZssoConfigResolver4個組件,以及默認實現類,接入方在接入過程當中能夠隨意拓展這4個組件,而後直接注入到業務層上下文便可。
UrlHelper:拼接url的組件,如無特殊需求不建議從新實現
ZssoClient:跟服務端交互的組件,如無特殊需求不建議從新實現
ZssoConfigResolver:解析配置文件的組件,默認實現是讀取本地classpath下zsso-client.properties配置文件,如無特殊需求不建議從新實現
UserStore:存取用戶信息的組件,包括根據token解析用戶信息,綁定token與userId關係,解綁token,默認實現只是爲了演示用,接入方請務必本身實現此接口,並以userStore的名稱注入到業務層上下文中。
拓展組件使用方式:
在spring掃描掉<zsso:auto-driven/>時會去回調ZssoNamespaceHandler的init方法,最終執行ZssoBeanDefinitionParser的parse方法,在此方法中會去檢查每一個組件是否有注入對應的BeanDefinition,若是沒有則會自動注入默認實現類,核心代碼以下:
至此組件初始化的問題已經解決了,另外須要接入方開發的是以下問題:
判斷登陸狀態
登陸成功回調接口(包括check token的邏輯)
登出回調接口
既然每一個接入方都有這樣的共性,因此我提供了一個ZssoFilter,在Filter里根據不一樣的url作不一樣的處理,接入方只須要配置此Filter便可,Filter內部會自動去獲取組件,接入方只須要拓展相關組件便可,ZssoFilter核心代碼以下:
LoginCallbackFilter已封裝好解析請求參數中token,check token,建立本地會話,跳轉到原頁面等功能
LoginCheckFilter已封裝好判斷當前用戶是否登陸及跳轉到登陸頁的邏輯
LogoutFilter已封裝好刪除本地會話的功能
代碼中不少代碼都是演示類的,尤爲是server端的實現,好比保持用戶信息都是存的本地緩存,若是要放到生成環境則須要優化下這塊的邏輯,好比放到redis這樣的分佈式緩存等等。
最後很是感謝你們能在百忙中抽空看個人文章,你們的每一次查看都是我繼續寫文章的動力,因爲本人是典型理科男,文筆可能欠妥,但願你們可以繼續支持我,我也會繼續努力,繼續堅持原創,希望能讓你們都能有所收穫!