上一篇對 Spring Security 全部內置的 Filter 進行了介紹。今天咱們來實戰如何安全退出應用程序。html
這個問題咱們必須搞清楚!通常登陸後,服務端會給用戶發一個憑證。常見有如下的兩種:前端
基於 Session
客戶端會存 cookie
來保存一個 sessionId
,服務端存一個 Session
。java
基於 token
客戶端存一個 token
串,服務端會在緩存中存一個用來校驗此 token
的信息。spring
permitAll
, 只有攜帶對應用戶的憑證才退出。接下來咱們來分析並實戰 如何定製退出登陸邏輯。首先咱們要了解 LogoutFilter
。編程
經過 Spring Security 實戰乾貨:內置 Filter 全解析 咱們知道退出登陸邏輯是由過濾器 LogoutFilter
來執行的。 它持有三個接口類型的屬性:json
RequestMatcher logoutRequestMatcher
這個用來攔截退出請求的 URL
LogoutHandler handler
用來處理退出的具體邏輯LogoutSuccessHandler logoutSuccessHandler
退出成功後執行的邏輯咱們經過對以上三個接口的實現就能實現咱們自定義的退出邏輯。後端
咱們通常不會直接操做 LogoutFilter
,而是經過 LogoutConfigurer
來配置 LogoutFilter
。 你能夠經過 HttpSecurity#logout()
方法來初始化一個 LogoutConfigurer
。 接下來咱們來實戰操做一下。緩存
LogoutConfigurer
提供了 logoutRequestMatcher(RequestMatcher logoutRequestMatcher)
、logoutUrl(Sring logoutUrl)
兩種方式來定義退出登陸請求的 URL
。它們做用是相同的,你選擇其中一種方式便可。安全
默認狀況下 Spring Security 是基於 Session
的。LogoutConfigurer
提供了一些直接配置來知足你的須要。以下:cookie
clearAuthentication(boolean clearAuthentication)
是否在退出時清除當前用戶的認證信息deleteCookies(String... cookieNamesToClear)
刪除指定的 cookies
invalidateHttpSession(boolean invalidateHttpSession)
是否移除 HttpSession
若是上面知足不了你的須要就須要你來定製 LogoutHandler
了。
logoutSuccessUrl(String logoutSuccessUrl)
退出成功後會被重定向到此 URL
,你能夠寫一個Controller 來完成最終返回,可是須要支持 GET
請求和 匿名訪問 。 經過 setDefaultTargetUrl
方法注入到 LogoutSuccessHandler
defaultLogoutSuccessHandlerFor(LogoutSuccessHandler handler, RequestMatcher preferredMatcher)
用來構造默認的 LogoutSuccessHandler
咱們能夠經過添加多個來實現從不一樣 URL
退出執行不一樣的邏輯。LogoutSuccessHandler logoutSuccessHandler
退出成功後執行的邏輯的抽象根本接口。如今先後端分離比較多,退出後返回json。 並且只有用戶在線才能退出登陸。不然不能進行退出操做。咱們採用實現 LogoutHandler
和 LogoutSuccessHandler
接口這種編程的方式來配置 。退出請求的 url
依然經過 LogoutConfigurer#logoutUrl(String logoutUrl)
來定義。
默認狀況下清除認證信息 (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 等等。
若是咱們實現了自定義的 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(); } }
爲了方便調試我 註釋掉了咱們 實現的自定義登陸,你能夠經過 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()); }
本篇 咱們實現了 在 Spring Security 下的自定義退出邏輯。相對比較簡單,你能夠根據你的業務須要來實現你的退出邏輯。有什麼疑問能夠經過 關注公衆號:Felordcn 來私信提問 。相關DEMO代碼也能夠經過關注後回覆 ss04
獲取。
關注公衆號:Felordcn獲取更多資訊