本文共 4805 字,大约阅读时间需要 16 分钟。
上一篇对 Spring Security 所有内置的 进行了介绍。今天我们来实战如何安全退出应用程序。
这个问题我们必须搞清楚!一般登录后,服务端会给用户发一个凭证。常见有以下的两种:
基于 Session 客户端会存 cookie 来保存一个 sessionId ,服务端存一个 Session 。
基于 token 客户端存一个 token 串,服务端会在缓存中存一个用来校验此 token 的信息。
permitAll, 只有携带对应用户的凭证才退出。接下来我们来分析并实战 如何定制退出登录逻辑。首先我们要了解 LogoutFilter 。
通过 我们知道退出登录逻辑是由过滤器 LogoutFilter 来执行的。 它持有三个接口类型的属性:
RequestMatcher logoutRequestMatcher 这个用来拦截退出请求的 URLLogoutHandler handler 用来处理退出的具体逻辑LogoutSuccessHandler logoutSuccessHandler 退出成功后执行的逻辑我们通过对以上三个接口的实现就能实现我们自定义的退出逻辑。
我们一般不会直接操作 LogoutFilter ,而是通过 LogoutConfigurer 来配置 LogoutFilter。 你可以通过 HttpSecurity#logout() 方法来初始化一个 LogoutConfigurer 。 接下来我们来实战操作一下。
LogoutConfigurer 提供了 logoutRequestMatcher(RequestMatcher logoutRequestMatcher)、logoutUrl(Sring logoutUrl) 两种方式来定义退出登录请求的 URL 。它们作用是相同的,你选择其中一种方式即可。
默认情况下 Spring Security 是基于 Session 的。LogoutConfigurer 提供了一些直接配置来满足你的需要。如下:
clearAuthentication(boolean clearAuthentication) 是否在退出时清除当前用户的认证信息deleteCookies(String... cookieNamesToClear) 删除指定的 cookiesinvalidateHttpSession(boolean invalidateHttpSession) 是否移除 HttpSession如果上面满足不了你的需要就需要你来定制 LogoutHandler 了。
logoutSuccessUrl(String logoutSuccessUrl) 退出成功后会被重定向到此 URL ,你可以写一个Controller 来完成最终返回,但是需要支持 GET 请求和 匿名访问 。 通过 setDefaultTargetUrl 方法注入到 LogoutSuccessHandlerdefaultLogoutSuccessHandlerFor(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获取更多资讯
转载地址:http://xpjuz.baihongyu.com/