注:Springsecurity版本4.3.x.RELEASE
先上一张LogoutFilter的类继承图,如下图1所示,原图见我的Github。
图1
LogoutFilter和其它Springsecurity的Filter一样,都是继承自GenericFilterBean。
来看下LogoutFilter的属性和构造方法,如下List-1所示。当我们定义了如List-2所示的bean时,调用的是List-1中的第二个构造方法。
List-1
public class LogoutFilter extends GenericFilterBean {
private RequestMatcher logoutRequestMatcher;
private final LogoutHandler handler;
private final LogoutSuccessHandler logoutSuccessHandler;
/**
* Constructor which takes a LogoutSuccessHandler instance to determine the
* target destination after logging out. The list of LogoutHandlers are
* intended to perform the actual logout functionality (such as clearing the security
* context, invalidating the session, etc.).
*/
public LogoutFilter(LogoutSuccessHandler logoutSuccessHandler,
LogoutHandler... handlers) {
this.handler = new CompositeLogoutHandler(handlers);
Assert.notNull(logoutSuccessHandler, "logoutSuccessHandler cannot be null");
this.logoutSuccessHandler = logoutSuccessHandler;
setFilterProcessesUrl("/logout");
}
public LogoutFilter(String logoutSuccessUrl, LogoutHandler... handlers) {
this.handler = new CompositeLogoutHandler(handlers);
Assert.isTrue(
!StringUtils.hasLength(logoutSuccessUrl)
|| UrlUtils.isValidRedirectUrl(logoutSuccessUrl),
() -> logoutSuccessUrl + " isn't a valid redirect URL");
SimpleUrlLogoutSuccessHandler urlLogoutSuccessHandler = new SimpleUrlLogoutSuccessHandler();
if (StringUtils.hasText(logoutSuccessUrl)) {
urlLogoutSuccessHandler.setDefaultTargetUrl(logoutSuccessUrl);
}
logoutSuccessHandler = urlLogoutSuccessHandler;
setFilterProcessesUrl("/logout");
}
List-2
来看下LogoutFilter的doFilter方法,如下List-3所示,
List-3
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (requiresLogout(request, response)) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (logger.isDebugEnabled()) {
logger.debug("Logging out user '" + auth + "' and transferring to logout destination");
}
this.handler.logout(request, response, auth);
logoutSuccessHandler.onLogoutSuccess(request, response, auth);
return;
}
chain.doFilter(request, response);
}
在List-3中:
requiresLogout方法判断requst中的url是否是/logout/cas,见List-2中的属性filterProcessesUrl
如果满足步骤1的要求,那么调用LogoutHandler的logout方法,会将Session失效,此外将SecurityContextHolder清空
如果满足步骤1的要求,那么调用LogoutSuccessHandler的onLogoutSuccess方法,设置HttpServletResponse的重定向
如果满足步骤1的要求,那么不会调用FilterChain了
来看下SecurityContextLogoutHandler的logout方法,如下List-4所示,
List-4
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
Assert.notNull(request, "HttpServletRequest required");
if (invalidateHttpSession) {
HttpSession session = request.getSession(false);
if (session != null) {
logger.debug("Invalidating session: " + session.getId());
session.invalidate();
}
}
if (clearAuthentication) {
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(null);
}
SecurityContextHolder.clearContext();
}
在List-4中:
会将HttpSession失效
清空SecurityContextHolder的context