[5] LogoutFilter

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));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章