單點登出原理
我們想實作單點登出,首先會想到在目前應用下把Session銷毀即可,但是仔細一想,這樣的話,是不能實作把與之共享一個token的應用的Session銷毀,這條路不行。
那既然所有的應用登入都需要通過一個驗證服務端,那麼登出的時候也通過該服務端,向所有用戶端發送登出請求即可實作

代碼實作
根據原理圖,我們想讓服務端(
sso-server
)儲存使用者的token在登入的時候已經實作,但現在還需要儲存登出位址(用戶端位址),使用者的session(sessionid),是以我們可以通過一個對象來儲存這兩個資訊,如下在服務端建立一個
ClientInfoVo
對象
@Data
public class ClientInfoVo {
private String clientUrl;
private String jsessionid;
}
有了對象,還需要将其儲存到模拟的資料庫中,是以在上一篇中的
MockDB
中添加一個資料結構,如下
當我們第一次登入時,需要到
/verify
判斷token是否有效,是以,我們可以在校驗token成功情況下将
clientUrl
和
jsessionid
存到模拟資料庫中,而首先,需要将兩者資訊攜帶過去
接下來就是在校驗token成功時将攜帶過來的資訊儲存到模拟資料庫中,如下
至此,完成了攜帶登出資訊并儲存的過程
當我們點選登出按鈕時,應該到服務端進行銷毀session并通過服務端向所有用戶端發起請求銷毀用戶端session,這就需要我們在登入的時候就把登出位址(服務端登出請求)攜帶,如下在用戶端登入時攜帶上了服務端登出位址
其中擷取登出位址的工具類如下,即服務端和用戶端位址加上
/logOut
請求
現在當我們點選登出時,就對到服務端
www.sso;8081/logOut
請求,到這裡銷毀服務端session,如下到
SsoServerController
類中添加如下代碼
@RequestMapping("/logOut")
public String logOut(HttpSession session){
session.invalidate();
return "login";
}
服務端session銷毀了,我們還需要發起請求讓所有用戶端的session銷毀,這裡可以通過服務端的一個session監聽器實作,如下
public class MySessionListener implements HttpSessionListener {
//session建立時候執行的操作
public void sessionCreated(HttpSessionEvent se) {
}
//session銷毀時候執行的操作
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
String token = (String) session.getAttribute("token");
//銷毀表中資料
MockDB.T_TOKEN.remove(token);
List<ClientInfoVo> clientInfoVos = MockDB.T_CLIENT_INFO.remove(token);
//周遊讓驗證服務端通知所有用戶端銷毀session
for (ClientInfoVo infoVo : clientInfoVos) {
try {
HttpUtil.sendHttpRequest(infoVo.getClientUrl(),infoVo.getJsessionid());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
并在
web.xml
中注冊監聽器
<!--監聽器注冊-->
<listener>
<listener-class>com.ranran.listener.MySessionListener</listener-class>
</listener>
既然服務端要周遊通知所有用戶端銷毀session,那麼所有用戶端也需要銷毀session的方法
至此,已經完成了單點登出。