1. 程式人生 > >如何設計一個單點登錄系統(3)?

如何設計一個單點登錄系統(3)?

抽象 pat resolve pro 業務 問題 resolv -c cli

在上一篇文章

如何設計一個單點登錄系統(2)?

中主要講解了可跨域SSO系統服務端,客戶端在登錄,登出過程中分別應該承擔的職責,本文將重點聊一下具體技術實現,源碼地址: https://github.com/zhoudapeng/zsso

首先聊服務端的實現,畢竟服務端是整個單點登錄系統的大腦

  1. 提供登錄頁,這個是登錄的基礎,所有的接入方在發現當前用戶未登錄的情況下都會重定向到sso服務端的登錄頁,服務端的邏輯如下:

技術分享圖片

sso服務端登錄頁邏輯

這裏服務端需要做個判斷:

  • 如果當前登錄存在.sso.com域下的有效cookie,則證明此用戶之前在其他業務系統登錄過,此時無需再讓用戶登錄,只需要綁定token與此系統名的關系,然後重定向到此系統的回調接口(接入方需要在此回調接口中驗證token,創建本地會話)

  • 不存在.sso.com域下的有效cookie,證明此用戶未登錄過,需要跳轉到登錄頁,讓用戶登錄,為了用戶登錄後能直接進入之前的頁面,這裏重定向的過程中需要帶上redirectUrl 這個參數

2.提供登錄接口,用戶在登錄頁輸入賬號密碼後會通過form表單已post的形式提交到此接口

技術分享圖片

sso服務端登錄form表單提交處理邏輯

  • 如果賬號密碼不對,則再次跳轉到登錄頁

  • 賬號密碼匹配,則需要創建token,綁定token與系統名的關系,寫全局cookie,然後重定向到接入方的回調地址

3.提供驗證token接口

技術分享圖片

sso服務端驗證token接口

  • token不存在,返回驗證失敗

  • token存在,則取出token的有效截止日期,並綁定token與系統名的關系

4.提供登出接口

技術分享圖片

sso服務端登出接口

登出時,需要根據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的名稱註入到業務層上下文中。

拓展組件使用方式:

技術分享圖片

拓展UserStore組件配置方式

在spring掃描掉<zsso:auto-driven/>時會去回調ZssoNamespaceHandler的init方法,最終執行ZssoBeanDefinitionParser的parse方法,在此方法中會去檢查每個組件是否有註入對應的BeanDefinition,如果沒有則會自動註入默認實現類,核心代碼如下:

技術分享圖片

ZssoBeanDefinitionParser核心代碼

技術分享圖片

ComponentInitializer核心代碼

至此組件初始化的問題已經解決了,另外需要接入方開發的是如下問題:

  1. 判斷登錄狀態

  2. 登錄成功回調接口(包括check token的邏輯)

  3. 登出回調接口

既然每個接入方都有這樣的共性,所以我提供了一個ZssoFilter,在Filter裏根據不同的url做不同的處理,接入方只需要配置此Filter即可,Filter內部會自動去獲取組件,接入方只需要拓展相關組件即可,ZssoFilter核心代碼如下:

技術分享圖片

ZssoFilter核心邏輯

LoginCallbackFilter已封裝好解析請求參數中token,check token,創建本地會話,跳轉到原頁面等功能

LoginCheckFilter已封裝好判斷當前用戶是否登錄及跳轉到登錄頁的邏輯

LogoutFilter已封裝好刪除本地會話的功能

代碼中很多代碼都是演示類的,尤其是server端的實現,比如保持用戶信息都是存的本地緩存,如果要放到生成環境則需要優化下這塊的邏輯,比如放到redis這樣的分布式緩存等等。

最後非常感謝大家能在百忙中抽空看我的文章,大家的每一次查看都是我繼續寫文章的動力,由於本人是典型理科男,文筆可能欠妥,希望大家能夠繼續支持我,我也會繼續努力,繼續堅持原創,但願能讓大家都能有所收獲!

如何設計一個單點登錄系統(3)?