上一篇对 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获取更多资讯