1、http無狀態協定
web應用程式採用browser/server架構,http作為通訊協定。 http是無狀態協議,瀏覽器的每一個請求,伺服器會獨立處理,不與之前或之後的請求產生關聯,這個過程用下圖說明,三次請求/回應對之間沒有任何聯繫
# 但這也同時意味著,任何使用者都能透過瀏覽器存取伺服器資源,如果想保護伺服器的某些資源,必須限制瀏覽器請求;要限制瀏覽器請求,必須鑑別瀏覽器請求,回應合法請求,忽略非法請求;要鑑別瀏覽器請求,必須清楚瀏覽器請求狀態。既然http協定無狀態,那就讓伺服器和瀏覽器共同維護一個狀態吧!這就是會話機制
瀏覽器第一次請求伺服器,伺服器建立一個會話,並將會話的id作為回應的一部分傳送給瀏覽器,瀏覽器存儲會話id,並在後續第二次和第三次請求中帶上會話id,伺服器取得請求中的會話id就知道是不是同一個用戶了,這個過程用下圖說明,後續請求與第一次請求產生了關聯
伺服器在記憶體中保存會話對象,瀏覽器怎麼保存會話id呢?你可能會想到兩種方式
請求參數
#cookie
將會話id作為每一個請求的參數,伺服器接收請求自然能解析參數獲得會話id,並藉此判斷是否來自同一會話,很明顯,這種方式不靠譜。那就瀏覽器自己來維護這個會話id吧,每次發送http請求時瀏覽器自動發送會話id,cookie機制正好用來做這件事。 cookie是瀏覽器用來儲存少量資料的機制,資料以」key/value「形式存儲,瀏覽器發送http請求時自動附帶cookie訊息
tomcat會話機制當然也實作了cookie,存取tomcat伺服器時,瀏覽器中可以看到一個名為「JSESSIONID」的cookie,這就是tomcat會話機制維護的會話id,使用了cookie的請求回應過程如下圖
有了會話機制,登入狀態就好明白了,我們假設瀏覽器第一次請求伺服器需要輸入使用者名稱與密碼驗證身份,伺服器拿到使用者名稱密碼去資料庫比對,正確的話說明目前持有這個會話的用戶是合法用戶,應該將這個會話標記為「已授權」或「已登入」等等之類的狀態,既然是會話的狀態,自然要保存在會話物件中,tomcat在會話物件中設定登入狀態如下
#1 ##2 |
HttpSession session = request.getSession();session.setAttribute("isLogin",true); |
1#2 | HttpSession session = request. getSession();session.getAttribute("isLogin"); |
##1#234#5#6 ##7 ##8 #910 |
1112
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {###### HttpServletRequest req = (HttpServletRequest) request;###### HttpServletResponse res =# (HttpServletResponse) HttpServletResponse res =# (HttpServletResponse) HttpSession session = req.getSession();
if(session.getAtNot ; return; # } //跳轉至sso認證中心 -url"); } |
3、sso-server驗證使用者登入資訊
2 3 4 5 #6 | @RequestMapping("/ login")
public String login(String username, String password, HttpServletRequest req) { this.checkLoginInfo(username, password); setAttribute("isLogin",true); return"success"; } |
String token = UUID.randomUUID().toString(); |
2 #3 4 5 6 7 8 9 1011 |
// 請求附帶token參數String token = req.getParameter("token"); if (token != null) { // 去sso認證中心校驗token booleanverifyResult = this.verify("sso-server-verify-url", token); if(!verifyResult) { ## res.sendRedirect("sso-server-url"); # chain.doFilter(request, response); } | # verify()方法使用httpClient實現,這裡僅簡略介紹,httpClient詳細使用方法請參考官方文件
HttpPost httpPost =new HttpPost(" sso-server-verify-url-with-token"); | HttpResponse httpResponse = httpClient.execute(httpPost);6、 |
令牌與註冊系統位址可以用下圖描述的結構儲存在redis中,可能你會問,為什麼要儲存這些系統的位址?如果不存儲,註銷的時候就麻煩了,用戶向sso認證中心提交註銷請求,sso認證中心註銷全局會話,但不知道哪些系統用此全局會話建立了自己的局部會話,也不知道要向哪些子系統發送註銷請求註銷局部會話
7、sso-client校驗令牌成功建立局部會話1 |
sso-client還需將目前會話id與令牌綁定,表示這個會話的登入狀態與令牌相關,此關係可以用java的hashmap保存,保存的資料用來處理sso認證中心發送的註銷請求
用戶向子系統發送帶有“logout”參數的請求(註銷請求),sso-client攔截器攔截該請求,向sso認證中心發起註銷請求
1 2 3 4 |
#String logout = req.getParameter("logout"); if (logout != null) { this.ssoServer.logout(token); #} |
sso認證中心也用同樣的方式辨識出sso-client的要求是註銷要求(有「logout」參數),sso認證中心註銷全域會話
1 2 3 ##45 678 |
#@RequestMapping("/logout")public String logout (HttpServletRequest req) { HttpSession session = req.getSession(); if(session != null) {# #2;215/71/L1808500% } return"redirect:/";} |
3 4 5 6 #7 8 public class LogoutListener implementsHttpSessionListener { | @Override
publicvoid sessionCreated(HttpSession SessionEvent event) { //通過httpClient向所有註冊系統發送註銷請求 } } 相關推薦: |
以上是實例講解SSO單一登入原理的詳細內容。更多資訊請關注PHP中文網其他相關文章!