LogoutFilter
介绍
LogoutFilter是一个处理登出请求的过滤器,当请求经过LogoutFilter时,过滤器会请判断当前请求的URL是否是登出URL,如果匹配,就执行遍历执行处理登出的handlers。默认情况下,会清空SecurityContextHolder的身份认证信息,以及发送一个登出成功的事件。
代码分析
步骤1
LogoutFilter默认登出URL是/logout,但是对于一些项目而言,并一定是/logout,如果特殊的定制化需求,可以通过WebSecurityConfigurerAdapter进行配置,LogoutFilter构造器和配置代码如下:
public LogoutFilter(LogoutSuccessHandler logoutSuccessHandler,
LogoutHandler... handlers) {
this.handler = new CompositeLogoutHandler(handlers);
Assert.notNull(logoutSuccessHandler, "logoutSuccessHandler cannot be null");
this.logoutSuccessHandler = logoutSuccessHandler;
//默认登出URL是/logout
setFilterProcessesUrl("/logout");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.logout().logoutUrl("/oauth2/token/remove");
}
步骤2
doFilter()首先对request的url与配置的登出的url进行比对,若是配置的退出登录的url则与request中的url不一致,则直接执行过滤链的后续过滤器,反之则进行退出登录操作。从上下文中取出身份认证信息,然后通过注入的handler进行处理,LogoutFilter的handler是一个复合类型的handler,这个handler一个handler list,对请求和身份认证信息一次进行处理,handler list默认情况包含2个handler,SecurityContextLogoutHandler和LogoutSuccessEventPublishingLogoutHandler。前者用于清除上下文中的身份认证信息以及清空上下文,后者在用于发送一个退出登录的spring事件。
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//判断是否需要进行登出操作,里边主要进行了一次URL匹配操作
if (requiresLogout(request, response)) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
//这是一个复合的handler, 这个handler里维护一个handler list,遍历执行每一个handler的logout
this.handler.logout(request, response, auth);
//默认情况下,它是一个SimpleUrlLogoutSuccessHandler,重定向的/login?logout
logoutSuccessHandler.onLogoutSuccess(request, response, auth);
return;
}
chain.doFilter(request, response);
}
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();
}
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
if (eventPublisher == null) {
return;
}
if (authentication == null) {
return;
}
//发送一个Spring事件
eventPublisher.publishEvent(new LogoutSuccessEvent(authentication));
}