sso單點登錄

需求:

當一個應用下有好多子系統都需要來驗證用戶,如果每次都需要用戶去輸入密碼來驗證,第一用戶會瘋的,客戶體驗度不好,第二,各個子系統的驗證邏輯也會出現問題;所以就需要設計一套實現在一個用戶只需要登錄一次就可以再次登錄另外子系統

解決方法:

  • 單系統:

    登錄解決方法使用Cookie來實現客戶端與服務端之間用戶會話數據,但是cookie會話機制是有限制的,體現在cookie的域(網站的域名),即每次客戶端向服務端傳遞的cookie數據是在某個域名下的數據,而不是所有的數據,所以,如果多系統cookie無法來實現。

  • 多系統:

    早起採用:採用同域名共享cookie方式來實現
    侷限性:
    1. 應用系統域名必須統一;
    2.各個系統使用(至少web容器)的開發技術相同,不然cookie值爲不一樣,無法維持會話,cookie的方式是無法實現跨語言技術平臺登錄的,比如java、php、.net系統之間
    3. cookie本身不安全

    現在:單點登錄全稱Single Sign On(以下簡稱SSO),是指在多系統應用羣中登錄一個系統,便可在其他所有系統中得到授權而無需再次登錄,包括單點登錄與單點註銷兩部分。

原理

:sso需要一個認證中心,只要認證中心驗證通過的用戶名,登陸子系統不需要再次驗證,直接登陸。
這裏寫圖片描述

當用戶訪問系統1時,發現系統未登陸,則跳轉認證中心(攜帶子系統網站連接作爲參數)登陸,驗證通過,會生成授權令牌,用戶和sso形成全局會話;

驗證通過後,sso系統重定向將系統1登陸成功的頁面,系統1使用令牌和用戶創建局部會話

當訪問系統2時,發現該用戶未登錄,則跳轉到認證中,認證中心發現已經登陸,跳轉回系統2的登陸頁面,並附上令牌,然後跳轉到認證中心驗證令牌是否有效,有效的進入系統2登陸頁面。

用戶登錄成功之後,會與sso認證中心及各個子系統建立會話,用戶與sso認證中心建立的會話稱爲全局會話,用戶與各個子系統建立的會話稱爲局部會話,局部會話建立之後,用戶訪問子系統受保護資源將不再通過sso認證中心,全局會話與局部會話有如下約束關係

  • 局部會話存在,全局會話一定存在
  • 全局會話存在,局部會話不一定存在
  • 全局會話銷燬,局部會話必須銷燬

實現

基於java實現
代碼主要分爲子系統登陸認證和sso認證系統登陸驗證

登陸實現

子系統登陸filter

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;
    HttpSession session = req.getSession();

    if (session.getAttribute("isLogin")) {
        chain.doFilter(request, response);
        return;
    }
    //跳轉至sso認證中心,攜帶子系統的url連接參數
    res.sendRedirect("sso-server-url-with-system-url");
}

子系統獲取sso認證中心的token值來驗證

//緊接上面的filter
// 請求附帶token參數
String token = req.getParameter("token");
if (token != null) {
    // 去sso認證中心校驗token
    boolean verifyResult = this.verify("sso-server-verify-url", token);
    if (!verifyResult) {
        res.sendRedirect("sso-server-url");
        return;
    }
    //如果驗證成功則標記當前對話爲已登錄狀態
    if (verifyResult) {
        session.setAttribute("isLogin", true);
    }
    chain.doFilter(request, response);
}

verify方法,使用httpClient,需要從新發起http請求驗證
http://tzz6.iteye.com/blog/2224757
https://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2112804.html

HttpPost httpPost = new HttpPost("sso-server-verify-url-with-token");
HttpResponse httpResponse = httpClient.execute(httpPost);

sso-client還需將當前會話id與令牌綁定,表示這個會話的登錄狀態與令牌相關,此關係可以用java的hashmap保存,保存的數據用來處理sso認證中心發來的註銷請求

sso認證中心和子系統攔截一樣

sso認證中心認證代碼和令牌指定

@RequestMapping("/login")
public String login(String username, String password, HttpServletRequest req) {
    //認證用戶名是否正確和存在
    this.checkLoginInfo(username, password);
    //設置用戶已登錄屬性
    req.getSession().setAttribute("isLogin", true);
    //設置令牌值,這裏只要區分爲該用戶一個token值即可
    String token = UUID.randomUUID().toString();
    return "success";
}

註銷實現

子系統filter

String logout = req.getParameter("logout");
if (logout != null) {
    this.ssoServer.logout(token);
}

sso認證中心

@RequestMapping("/logout")
public String logout(HttpServletRequest req) {
    HttpSession session = req.getSession();
    if (session != null) {
        session.invalidate();//觸發LogoutListener
    }
    return "redirect:/";
}

??????
sso認證中心有一個全局會話的監聽器,一旦全局會話註銷,將通知所有註冊系統註銷

public class LogoutListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent event) {}
    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        //通過httpClient向所有註冊系統發送註銷請求
    }
}
發佈了63 篇原創文章 · 獲贊 17 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章