借助xxl-sso實現SSO


前言

市場上一下主流的SSO技術搭配方案:

  1. SpringSecurity + OAuth2
  2. SpringSecurity + CAS 功能較弱,對前后端分離的項目支持不是很好
  3. Shiro + CAS
  4. JWT 可以自定義需求,靈活擴展鑒權方式

本篇主要是單點登錄,不涉及鑒權,后面文章會再補充

xxl-sso 是一個國產 SSO 框架,基於 cookies 實現,也許你會考慮跨域問題,雖然 cookies 本身不跨域,但可以利用它實現跨域的 SSO。

1、拉取官方示例項目

gitee地址:https://gitee.com/xuxueli0323/xxl-sso
github地址:https://github.com/xuxueli/xxl-sso

模塊說明:
  • xxl-sso-server:中央認證服務,支持集群
  • xxl-sso-core:Client端依賴
  • xxl-sso-samples:單點登陸Client端接入示例項目
    • xxl-sso-web-sample-springboot:基於Cookie接入方式,供用戶瀏覽器訪問,springboot版本
    • xxl-sso-token-sample-springboot:基於Token接入方式,常用於無法使用Cookie的場景使用,如APP、Cookie被禁用等,springboot版本
依賴環境:

JDK:1.7+
Redis:4.0+

修改本地host:
127.0.0.1 xxlssoserver.com
127.0.0.1 xxlssoclient1.com
127.0.0.1 xxlssoclient2.com
導入項目后啟動:

修改 application.properties redis為本地地址后啟動 xxl-sso-server:

### xxl-sso
xxl.sso.redis.address=redis://127.0.0.1:6378
xxl.sso.redis.expire.minite=1440

完美報錯,如果你跟我上圖一樣,那么說明你的 redis 設置了密碼,這個官方示例代碼是沒有配置 redis 密碼的,看控制台:

我們可以看到初始化時用到了 redis 的本地地址,那么只需要知道在哪用了這個地址,那么肯定就會有設置密碼的地方。

果不其然,我們最終發現了,地址是通過 JedisShardInfo 這個對象傳遞進去的,進入這個對象后發現,竟然有個 password?這不就是我們要找的密碼嗎。

再次啟動,成功啟動。

同樣的修改 xxl-sso-samples > xxl-sso-web-samples-sprigboot 的 properties 然后再啟動。

2、認證流程

客戶端端口號被我改成8085,認證中心保持默認端口號8080

屆時,我們啟動了兩個項目,瀏覽器訪問第一個域名:http://xxlssoclient1.com:8085/xxl-sso-web-sample-springboot

我們可以看到訪問后將被重定向到認證中心 http://xxlssoserver.com:8080/xxl-sso-server ,后面攜帶參數 redirect_url ,其為界面跳轉前的鏈接,認證通過后將再次重定向回原來的訪問鏈接。

上圖為認證成功后的圖片,會攜帶 xxl_sso_sessionid,其用於識別用戶登陸信息,並會保存至本地兩份 cookie,皆用來保存 xxl_sso_sessionid ,一份當前域名(xxlssoclient1.com),一份認證中心(xxlssoserver.com)。

保存的兩份 xxl_sso_sessionid 值是一樣的。

xxl_sso_sessionid由來

在上圖中的認證界面,點擊登錄后會調用 WebController > doLogin 方法,用戶登錄成功后會生成該用戶的 xxl_sso_sessionid 信息,並保存至 redis 中,同時會把 xxl_sso_sessionid 寫入客戶端 cookie,然后將重定向到 redirect_url,並拼接 xxl_sso_sessionid 參數,如下圖所示。

我們再來訪問第二個客戶端試試,http://xxlssoclient2.com:8085/xxl-sso-web-sample-springboot,就目前並未向 http://xxlssoclient2.com:8085 寫入任何有關 cookie 用戶會話信息:

神奇的一幕發生了,顯然2號客戶端也成功登陸了,並攜帶了跟客戶端1一樣的 xxl_sso_sessionid 信息,我們再來看一下 cookie 信息:

xxlssoclient2.com中的xxl_sso_sessionid哪里來的?

其實通過 debug 發現,在 xxlssoclient1.com 登陸的前提下,再去訪問 xxlssoclient2.com 時,由於沒有任何登陸信息同樣也是首先會跳轉至認證中心:

還記得客戶端1登陸后在認證中心 xxlssoserver.com 同樣留下 xxl_sso_sessionid 信息嗎?

顯然,客戶端2號再跳轉過來時復用了認證中心的 xxl_sso_sessionid,然后發現存在 xxl_sso_sessionid,且 xxl_sso_sessionid 在 redis 里也沒過期,則認為用戶已經登陸了,重新重定向到 xxlssoclient2.com

退出操作

看完了統一登錄,再來看一下退出操作。

退出相對就比較簡單了,主要就是驗證 redis 中的 xxl_sso_sessionid,我們來看一下退出方法:

首先調用退出方法后會清空當前網站的 cookie、redis 中的 xxl_sso_sessionid,比如在 xxlssoclient1.com、xxlssoclient2.com 都登陸的情況下,通過 xxlssoclient2.com 退出當前用戶,則首先會清空 xxlssoclient2.com 站點下的 cookie ,同時后台也會清空當前用戶的 redis,那么再通過 xxlssoclient1.com 訪問時,盡管攜帶 xxl_sso_sessionid,但此時該信息已經過期,所以會再次重定向認證中心。

xxl-sso小結

如上為 xxl-sso 架構圖,其核心為:

sso-server:中央認證服務
sso-client:接入 sso 認證中心的客戶端應用
sso-sessionId:登陸用戶會話ID,SSO 登陸成功后為用戶自動分配
sso-user:登陸用戶信息,與 SSO sessionId 相對應

登陸流程剖析:
  1. 客戶端訪問受限資源時,將會自動重定向到 SSO Server 進入統一登錄界面
  2. 用戶登錄成功之后將會為用戶分配 SSO SessionId 並重定向返回來源客戶端端應用,同時附帶分配的 SSO SessionId
  3. 在客戶端的 SSO 過濾器里驗證 SSO SessionId 無誤,將 SSO SessionId 寫入到用戶瀏覽器客戶端域名下 cookie 中
  4. SSO 過濾器驗證 SSO SessionId 通過,受限資源請求放行
注銷流程剖析:
  1. 用戶在客戶端應用請求注銷時,將會重定向到 SSO Server 自動銷毀全局 SSO SessionId,實現全局銷毀用戶登陸信息;
  2. 然后,訪問接入SSO 保護的任意客戶端應用時,SSO 過濾器均會攔截請求並重定向到 SSO Server 的統一登錄界面;

至此,通過 cookie+redis 解決了多端統一認證,全局 sessionId 解決了 session 共享的問題。

基於Cookie,相關概念
  • 登陸憑證存儲:登陸成功后,用戶登陸憑證被自動存儲在瀏覽器Cookie中
  • 客戶端校驗登陸狀態:通過校驗請求Cookie中的是否包含用戶登錄憑證判斷
  • 系統角色模型:
    -- SSO Server:認證中心,提供用戶登陸、注銷以及登陸狀態校驗等功能
    -- 客戶端應用:受SSO保護的客戶端Web應用,為用戶瀏覽器訪問提供服務
    -- 用戶:發起請求的用戶,使用瀏覽器訪問

如果 Cookie 被禁用怎么辦?

xxl-sso 同樣提供了 基於 token 接入方式,用於無法使用Cookie的場景使用,如APP、Cookie被禁用等,詳細可參考 xxl-sso-token-sample-springboot 項目。

基於Token,相關概念
  • 登陸憑證存儲:登陸成功后,獲取到登錄憑證(xxl_sso_sessionid=xxx),需要主動存儲,如存儲在 localStorage、Sqlite 中
  • 客戶端校驗登陸狀態:通過校驗請求 Header參數 中的是否包含用戶登錄憑證(xxl_sso_sessionid=xxx)判斷;因此,發送請求時需要在 Header 參數 中設置登陸憑證
  • 系統角色模型:
    -- SSO Server:認證中心,提供用戶登陸、注銷以及登陸狀態校驗等功能
    --客戶端應用:受SSO保護的客戶端Web應用,為用戶請求提供接口服務
    -- 用戶:發起請求的用戶,如使用Android、IOS、桌面客戶端等請求訪問

更多信息請訪問官方文檔:http://www.xuxueli.com/xxl-sso/#/

后面會寫一篇實際項目中接入 xxl-sso 框架的實例。

我創建了一個java相關的公眾號,用來記錄自己的學習之路,感興趣的小伙伴可以關注一下微信公眾號哈:niceyoo


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM