Spring Security 实战干货:实现自定义退出登录
文章目錄
1. 前言2. 我們使用 Spring Security 登錄后都做了什么2. 退出登錄需要我們做什么3. Spring Security 中的退出登錄3.1 LogoutFilter3.2 LogoutConfigurer3.2.1 實現自定義退出登錄請求URL3.2.2 處理具體的邏輯3.2.3 退出成功邏輯3.3 Spring Security 退出登錄實戰3.3.1 自定義 LogoutHandler3.3.2 自定義 LogoutSuccessHandler3.3.4 自定義退出的 Spring Security 配置4. 總結
1. 前言
上一篇對 Spring Security 所有內置的 Filter 進行了介紹。今天我們來實戰如何安全退出應用程序。
2. 我們使用 Spring Security 登錄后都做了什么
這個問題我們必須搞清楚!一般登錄后,服務端會給用戶發一個憑證。常見有以下的兩種:
基于 Session 客戶端會存 cookie 來保存一個 sessionId ,服務端存一個 Session 。
基于 token 客戶端存一個 token 串,服務端會在緩存中存一個用來校驗此 token 的信息。
2. 退出登錄需要我們做什么
當前的用戶登錄狀態失效。這就需要我們清除服務端的用戶狀態。
退出登錄接口并不是 permitAll, 只有攜帶對應用戶的憑證才退出。
將退出結果返回給請求方。
退出登錄后用戶可以通過重新登錄來認證該用戶。
3. Spring Security 中的退出登錄
接下來我們來分析并實戰 如何定制退出登錄邏輯。首先我們要了解 LogoutFilter 。
3.1 LogoutFilter
通過 Spring Security 實戰干貨:內置 Filter 全解析 我們知道退出登錄邏輯是由過濾器 LogoutFilter 來執行的。 它持有三個接口類型的屬性:
RequestMatcher logoutRequestMatcher 這個用來攔截退出請求的 URL
LogoutHandler handler 用來處理退出的具體邏輯
LogoutSuccessHandler logoutSuccessHandler 退出成功后執行的邏輯
我們通過對以上三個接口的實現就能實現我們自定義的退出邏輯。
3.2 LogoutConfigurer
我們一般不會直接操作 LogoutFilter ,而是通過 LogoutConfigurer 來配置 LogoutFilter。 你可以通過 HttpSecurity#logout() 方法來初始化一個 LogoutConfigurer 。 接下來我們來實戰操作一下。
3.2.1 實現自定義退出登錄請求URL
LogoutConfigurer 提供了 logoutRequestMatcher(RequestMatcher logoutRequestMatcher)、logoutUrl(Sring logoutUrl) 兩種方式來定義退出登錄請求的 URL 。它們作用是相同的,你選擇其中一種方式即可。
3.2.2 處理具體的邏輯
默認情況下 Spring Security 是基于 Session 的。LogoutConfigurer 提供了一些直接配置來滿足你的需要。如下:
clearAuthentication(boolean clearAuthentication) 是否在退出時清除當前用戶的認證信息
deleteCookies(String... cookieNamesToClear) 刪除指定的 cookies
invalidateHttpSession(boolean invalidateHttpSession) 是否移除 HttpSession
如果上面滿足不了你的需要就需要你來定制 LogoutHandler 了。
3.2.3 退出成功邏輯
logoutSuccessUrl(String logoutSuccessUrl) 退出成功后會被重定向到此 URL ,你可以寫一個Controller 來完成最終返回,但是需要支持 GET 請求和 匿名訪問 。 通過 setDefaultTargetUrl 方法注入到 LogoutSuccessHandler
defaultLogoutSuccessHandlerFor(LogoutSuccessHandler handler, RequestMatcher preferredMatcher) 用來構造默認的 LogoutSuccessHandler 我們可以通過添加多個來實現從不同 URL 退出執行不同的邏輯。
LogoutSuccessHandler logoutSuccessHandler 退出成功后執行的邏輯的抽象根本接口。
3.3 Spring Security 退出登錄實戰
現在前后端分離比較多,退出后返回json。 而且只有用戶在線才能退出登錄。否則不能進行退出操作。我們采用實現 LogoutHandler 和 LogoutSuccessHandler 接口這種編程的方式來配置 。退出請求的 url 依然通過 LogoutConfigurer#logoutUrl(String logoutUrl)來定義。
3.3.1 自定義 LogoutHandler
默認情況下清除認證信息 (invalidateHttpSession),和Session 失效(invalidateHttpSession) 已經由內置的SecurityContextLogoutHandler 來完成。我們自定義的 LogoutHandler 會在SecurityContextLogoutHandler 來執行。
@Slf4j
public class CustomLogoutHandler implements LogoutHandler {
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
User user = (User) authentication.getPrincipal();
String username = user.getUsername();
log.info("username: {} is offline now", username);
}
}
以上是我們實現的 LogoutHandler 。 我們可以從 logout 方法的 authentication 變量中 獲取當前用戶信息。你可以通過這個來實現你具體想要的業務。比如記錄用戶下線退出時間、IP 等等。
3.3.2 自定義 LogoutSuccessHandler
如果我們實現了自定義的 LogoutSuccessHandler 就不必要設置 LogoutConfigurer#logoutSuccessUrl(String logoutSuccessUrl) 了。該處理器處理后會響應給前端。你可以轉發到其它控制器。重定向到登錄頁面,也可以自行實現其它 MediaType ,可以是 json 或者頁面
@Slf4j
public class CustomLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
User user = (User) authentication.getPrincipal();
String username = user.getUsername();
log.info("username: {} is offline now", username);
responseJsonWriter(response, RestBody.ok("退出成功"));
}
private static void responseJsonWriter(HttpServletResponse response, Rest rest) throws IOException {
response.setStatus(HttpServletResponse.SC_OK);
response.setCharacterEncoding("utf-8");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
ObjectMapper objectMapper = new ObjectMapper();
String resBody = objectMapper.writeValueAsString(rest);
PrintWriter printWriter = response.getWriter();
printWriter.print(resBody);
printWriter.flush();
printWriter.close();
}
}
3.3.4 自定義退出的 Spring Security 配置
為了方便調試我 注釋掉了我們 實現的自定義登錄,你可以通過 http:localhost:8080/login 來登錄,然后通過 http:localhost:8080/logout 測試退出。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.cors()
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
// .addFilterBefore(preLoginFilter, UsernamePasswordAuthenticationFilter.class)
// 登錄
.formLogin().loginProcessingUrl(LOGIN_PROCESSING_URL).successForwardUrl("/login/success").failureForwardUrl("/login/failure")
.and().logout().addLogoutHandler(new CustomLogoutHandler()).logoutSuccessHandler(new CustomLogoutSuccessHandler());
}
4. 總結
本篇 我們實現了 在 Spring Security 下的自定義退出邏輯。相對比較簡單,你可以根據你的業務需要來實現你的退出邏輯。有什么疑問可以通過 關注公眾號:Felordcn 來私信提問 。相關DEMO代碼也可以通過關注后回復 ss04 獲取。
關注公眾號:Felordcn獲取更多資訊
個人博客:https://felord.cn
總結
以上是生活随笔為你收集整理的Spring Security 实战干货:实现自定义退出登录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【代谢组学】1.代谢组学简介
- 下一篇: 神经网络识别车牌字符