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));
}