Spring Security 的主要功能都是[基于一系列的过滤器实现](Architecture :: Spring Security),而
LogoutFilter就是其中一个,用于完成用户登出的相关功能。本篇文章主要介绍LogoutFilter完成登出流程的细节以及如何完成一些定制化的功能。
LogoutFilter 处理登出请求的主要流程
主要代码:
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (requiresLogout(request, response)) {
Authentication auth = this.securityContextHolderStrategy.getContext().getAuthentication();
if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage.format("Logging out [%s]", auth));
}
this.handler.logout(request, response, auth);
this.logoutSuccessHandler.onLogoutSuccess(request, response, auth);
return;
}
chain.doFilter(request, response);
}
处理流程:
- 首先判断当前请求是否应该由 LogoutFilter 来处理
- 然后获取当前 SecurityContext 中的 Authentication
- 调用
LogoutHandler#logout(request, response, auth)方法 - 调用
LogoutSuccessHandler#onLogoutSuccess(request, response, auth)方法
LogoutHandler 与 LogoutSuccessHandler 的区别
-
LogoutHandler-
用于清除认证信息相关的,要保证成功,不能抛出异常
-
默认使用的实现类:
1.SecurityContextLogoutHandler主要用于是清除 session 信息(可配置)和 SecurityContext2.LogoutSuccessEventPublishingLogoutHandler,登出成功后发送一个包含登出前认证信息的LogoutSuccessEvent事件,用户可以监听此事件来完成诸如 用户登出日志或统计等相关功能
-
自定义实现类:
- 自己实现的实现类通过下文的方式配置添加,执行顺序在上述两个默认实现类之前
-
接口定义:
/** * Indicates a class that is able to participate in logout handling. * * <p> * Called by {@link LogoutFilter}. * * @author Ben Alex */ public interface LogoutHandler { /** * Causes a logout to be completed. The method must complete successfully. * @param request the HTTP request * @param response the HTTP response * @param authentication the current principal details */ void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication); }
-
-
LogoutSuccessHandler-
用于确定认证信息清除成功后的行为,如 redirect 或 forwarding 到特定页面等
-
没有配置的情况下默认使用
SimpleUrlLogoutSuccessHandler -
接口定义:
/** * Strategy that is called after a successful logout by the {@link LogoutFilter}, to * handle redirection or forwarding to the appropriate destination. * <p> * Note that the interface is almost the same as {@link LogoutHandler} but may raise an * exception. <tt>LogoutHandler</tt> implementations expect to be invoked to perform * necessary cleanup, so should not throw exceptions. * * @author Luke Taylor * @since 3.0 */ public interface LogoutSuccessHandler { void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException; }
-
Logout 行为相关的可配置项(配置 SecurityFilterChain 时的 HttpSecurity中配置)
- ·LogoutConfigurer· 用于配置 logout 的一些组件:
logoutUrl匹配 LogoutFilter 是否执行 默认 /logoutlogoutSuccessUrl登出成功后的重定向地址,默认 /login?logoutdeleteCookies要删除的 cookielogoutSuccessHandler登出成功后的处理器addLogoutHandlerSecurityContextLogoutHandler and LogoutSuccessEventPublishingLogoutHandler are added as last LogoutHandler instances by default.clearAuthentication是否清除 Authentication, 影响 SecurityContextLogoutHandler 的行为invalidateHttpSession是否 invalide session,影响 SecurityContextLogoutHandler 的行为
应用:如何实现前后端分离项目中前端页面登出后跳转回登出前页面
后端处理:
-
自定义 LogoutSeccessHandler 实现类,获取登出后要跳转的 redirect_uri 然后重定向到改地址
@Component public class CustomLogoutSuccessHandler implements LogoutSuccessHandler { @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { String redirect_uri = request.getParameter("redirect_uri"); request.getSession().invalidate(); response.sendRedirect(redirect_uri); } }
前端处理:
-
在请求 /logout 接口时拼接当前页面地址作为 redirect_uri 参数
// 清除 storage // stroge.clear(); // 跳转登出页 location.href = `${ssoUrl()}/logout?redirect_uri=` + location.href;