聊聊我在這家公司設計的SSO

最近小明遇到一個需求:須要將幾個獨立的系統(子系統)彙總到一個集中的系統(父系統)當中,當用戶在父系統登陸事後,再點擊這幾個子系統,就能夠免登陸跳轉到任意一個系統。當時一聽,duang~duang~就有不少方案涌進來(吹牛的),但只有下面這個方案獲得了leader的確定,現在已經在線上跑着了,接下來給你們覆盤一下。前端

看完這個需求,你們是否是第一感受就是:這不就是SSO(單點登陸)系統嘛?程序員

單點登陸(英語:Single sign-on,縮寫爲 SSO),又譯爲單一簽入,一種對於許多相互關連,可是又是各自獨立的軟件系統,提供訪問控制的屬性。當擁有這項屬性時,當用戶登陸時,就能夠獲取全部系統的訪問權限,不用對每一個單一系統都逐一登陸。這項功能一般是以輕型目錄訪問協議(LDAP)來實現,在服務器上會將用戶信息存儲到LDAP數據庫中。相同的,單一退出(single sign-off)就是指,只須要單一的退出動做,就能夠結束對於多個系統的訪問權限。redis

是的,沒錯,小明接到這個需求之後,總體思路也是按着SSO設想的,可是細想以後,發現不能徹底照搬,要考慮項目的實際狀況:好比已知的幾個子系統是以前的已經開發好的,不能大動干戈,須要平滑接入父系統,並且根據需求,SSO的功能也不必所有實現,簡而言之,就是一個閹割版的SSO。spring

小明只須要實現:用戶在父系統帳號密碼登陸後,經過點擊任意一個子系統的功能按鈕(不須要重複輸入帳號登陸)可以跳轉子系統功能頁便可。數據庫

設計流程

項目

一個簡單樸素的SpringBoot項目json

時序圖

說幹就幹,用戶輸入帳號密碼,請求SSO用戶登陸模塊進行帳號密碼校驗,校驗經過後創建全局會話,而且返回前端token憑證(我使用的是sessionId),跳轉其餘系統時攜帶token,其餘系統拿到token後,再調用SSO平臺進行token校驗,若是校驗經過,則用戶可在子系統內創建會話,用戶跳轉系統完成。下面給你們舉例SSO跳轉一個子系統的時序圖:後端

簡易版sso

在這裏插一嘴哈,我使用的流程圖工具是ProcessOn,是一款在線畫圖工具,很是適合畫各類示意圖,體驗極佳,若是你們想嘗試一下,可使用個人邀請連接註冊使用~服務器

整個流程圖如上面所示,下面主要針對各個功能點進行詳細說明。微信

SSO系統的登陸與會話保持

本次會話管理採用的是redis session,spring完美支持redis存儲session信息,此外還支持MONGODBJDBCHAZELCAST等存儲會話方式。經過redis存儲session,能夠知足集羣部署、分佈式系統的session共享(固然這些都是後話)。session

pom.xml依賴配置以下

<!--redis 依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--sessions 依賴-->
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>複製代碼

application.yml配置redis及session

spring:
  redis:
    host: 127.0.0.1
    password: 123456
    port: 6379
    timeout: 1500
    database: 0
    jedis:
      pool:
        max-active: 1000
        max-wait: -1
        max-idle: 10
        min-idle: 5
  # 設置session存儲類型爲redis 
  session:
    store-type: redis複製代碼

此時,redis存儲會話配置已經完成,但總以爲缺乏什麼,嗷,原來除此以外,咱們還須要設置session的有效時長,application.yml中的配置以下:

server:
  servlet:
    session:
        # 支持Duration表達式,此時表示120分鐘
      timeout: PT120M複製代碼

固然,咱們還須要在Springboot主方法經過@EnableRedisHttpSession開啓redis session

注意:若是上面配置的session有效時長不生效,咱們能夠在註解屬性上配置session有效時間(不瞞你們,我就是在此處配置才生效的)

@SpringBootApplication
// 開啓redis session ,而且設置session有效時長
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 7200)
public class XiaoMingApplication {

    public static void main(String[] args) {
        SpringApplication.run(XiaoMingApplication.class, args);
    }
}複製代碼

至此,sso系統的登陸及會話管理就完成啦。接下來看一下與其餘系統如何交互。

跳轉子系統

流程

若是SSO已經登陸 -> 用戶點擊某個子系統按鈕(和負責A系統的人員約定好的連接)發起get請求 -> A系統後端接收到請求 -> 調用SSO系統進行token校驗(下面會講到) -> 創建會話,例如

http://xxx/jump?token=123456複製代碼

這是一個在地址欄輸入的get請求,該接口須要特殊處理,後端攔截器須要放行。

參數說明

參數
說明
xxx
此處xxx爲域名,jump爲系統A提供的接口url地址,能夠自定義,須要約定告知
token 返回的校驗憑證

該接口其實就須要幹兩件事情:

  1. 請求SSO進行token校驗(相似以前的用戶、密碼登陸,只不過調用SSO平臺接口校驗);
  2. 創建本地會話(和帳號密碼登陸成功以後的創建會話方式一致)。
  3. 控制校驗經過後的頁面跳轉。

SSO爲子系統提供token校驗接口

上面講到SSO會暴漏一個token校驗接口,這一塊邏輯很簡單,就是拿着token去redis中查找對應的用戶信息是否存在。衆所周知,小明是一個懶人,爲了投機取巧,小明token的生成規則,就是session的id,所以,判斷用戶是否登陸,其實就是根據sessionId查找redis是否存在會話,此處有亮點。經過查看源碼,我發現這個功能,根本不用咱們本身去實現,spring已經想到咱們會用到。

spring提供了一個接口org.springframework.session.SessionRepository

package org.springframework.session;

public interface SessionRepository<S extends Session> {
    S createSession();

    void save(S var1);
    // 這個就是
    S findById(String var1);

    void deleteById(String var1);
}複製代碼

其中S findById(String var1)就是咱們要調用的方法,這個方法做用就是根據sessionId去會話中心查找會話對象,正是咱們所須要的,咱們只需經過@Autowired獲取,開箱即用~咱們一塊兒看一下業務代碼:

@Autowired
    private SessionRepository sessionRepository;
        @PostMapping("/checkToken")
    public BaseResponseFacade checkToken(@RequestBody UserLoginVo userLoginVo) {
        if (Objects.isNull(userLoginVo)) {
            return ResponseUtil.error(NEED_LOGIN);
        }
        String token = userLoginVo.getToken();
        Session session = sessionRepository.findById(token);
        if (Objects.isNull(session)) {
            return ResponseUtil.error(NEED_LOGIN);
        }
        AdverInfo adverInfo = JSON.parseObject(session.getAttribute("adverInfo"), AdverInfo.class);
        return ResponseUtil.success(adverInfo);
    }
SSO和子系統的交互文檔也貼出來給你們一睹爲快複製代碼

接口調用請求說明

  • 請求方式:POST
  • 請求格式:JSON
  • 請求地址
    • 測試:http:/xxx/checkToken
    • 正式:http://xxx/checkToken
  • POST數據示例
{
    "token": "123456"
}複製代碼
參數說明

參數
說明
xxx/checkToken xxx爲域名,checkToken爲營銷雲平臺提供的校驗接口地址
token
調用接口憑據

返回說明

正常時返回的json數據包示例

若是SSO校驗經過,則系統A能夠與與當前用戶創建本地會話,用戶正常進入系統

{
    "data":{
    "XXX":"XXX"
    },
    "errorMsg":"成功",
    "errorCode":0
}複製代碼

參數說明

參數
說明
errorCode 0:表示請求成功
errorMsg
返回碼說明
XXX
其餘相關信息

異常時返回的json數據包示例

當SSO後臺校驗失敗時返回參數以下

{
  "errorMsg": "NEED_LOGIN",
  "errorCode": 10
}複製代碼

參數說明

參數
說明
errorMsg
錯誤信息說明
errorCode 錯誤標誌

錯誤碼說明

錯誤碼 說明
1
系統繁忙
10
須要用戶登陸
500
服務器內部錯誤

小明設計的簡潔版sso就大抵如此,你們能夠做爲一個sso入門demo來看待😁,若是你們有什麼建議或問題,歡迎留言~你們也能夠關注微信公衆號「程序員小明」獲取更多資源~歡迎關注微信公衆號」程序員小明」,獲取更多資源。

相關文章
相關標籤/搜索