javascript
Spring Security 实战:实现自定义退出登录
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?來執行。
@Slf4jpublic class CustomLogoutHandler implements LogoutHandler {@Overridepublic 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?或者頁面
@Slf4jpublic class CustomLogoutSuccessHandler implements LogoutSuccessHandler {@Overridepublic 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?測試退出。
@Overrideprotected 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());}總結
以上是生活随笔為你收集整理的Spring Security 实战:实现自定义退出登录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Git从入门到熟悉
- 下一篇: 后台清理 清理cookie_清理枯木