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