1. 程式人生 > 其它 >Spring-security原始碼-Filter之LogoutFilter(十三)

Spring-security原始碼-Filter之LogoutFilter(十三)

負責處理登出相關邏輯,預設url對映是/logout

org.springframework.security.config.annotation.web.configurers.LogoutConfigurer 初始化

預設初始化處https://www.cnblogs.com/LQBlog/p/15508248.html#autoid-12-0-0

private void applyDefaultConfiguration(HttpSecurity http) throws Exception {
        //http本質也是build 這裡都是配置預設的config configure add CsrfConfigurer
http.csrf(); //預設增加一個WebAsyncManagerIntegrationFilter http.addFilter(new WebAsyncManagerIntegrationFilter()); //configures add ExceptionHandlingConfigurer http.exceptionHandling(); //configures add HeadersConfigurer http.headers(); //configures add SessionManagementConfigurer
http.sessionManagement(); //configure add SecurityContextConfigurer http.securityContext(); //configure add RequestCacheConfigurer http.requestCache(); ///configure add AnonymousConfigurer http.anonymous(); ///configure add ServletApiConfigurer http.servletApi();
//configure DefaultLoginPageConfigurer http.apply(new DefaultLoginPageConfigurer<>()); //configure LogoutConfigurer http.logout(); }

通過http.logout().addLogoutHandler() 可以自定義handler

LogoutFilter

    private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        //匹配是否能夠處理 預設是/logout
        if (requiresLogout(request, response)) {
            //從SecurityContextHolder 獲得Authentication資訊
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
            if (this.logger.isDebugEnabled()) {
                this.logger.debug(LogMessage.format("Logging out [%s]", auth));
            }
            /**
             * 呼叫CompositeLogoutHandler 他也實現了LogoutHandler 他只是一個統一的管理器
             * 內部迴圈呼叫LogoutHandler
             * 預設有三種
             * PersistentTokenBasedRememberMeServices <1>
             * SecurityContextLogoutHandler <2>
             * LogoutSuccessEventPublishingLogoutHandler<3>
             */
            this.handler.logout(request, response, auth);
            //處理登出成功的SimpleUrlLogoutSuccessHandler 比如重定向到登入頁
            this.logoutSuccessHandler.onLogoutSuccess(request, response, auth);
            return;
        }
        chain.doFilter(request, response);
    }

<1>

org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices#logout

    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        //清除cookile
        super.logout(request, response, authentication);
        if (authentication != null) {
            //刪除token
            this.tokenRepository.removeUserTokens(authentication.getName());
        }
    }

<2>

org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler#logout

 @Override
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        Assert.notNull(request, "HttpServletRequest required");
        if (this.invalidateHttpSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                //清空session
                session.invalidate();
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug(LogMessage.format("Invalidated session %s", session.getId()));
                }
            }
        }
        if (this.clearAuthentication) {
            //清空
            SecurityContext context = SecurityContextHolder.getContext();
            context.setAuthentication(null);
        }
        //清空
        SecurityContextHolder.clearContext();
    }

<3>

釋出一個spring的事件我們可以監聽這個事件 知道某個使用者登出了 參考:https://www.cnblogs.com/LQBlog/p/13878553.html#_label5

org.springframework.security.web.authentication.logout.LogoutSuccessEventPublishingLogoutHandler#logout

@Override
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        if (this.eventPublisher == null) {
            return;
        }
        if (authentication == null) {
            return;
        }
        this.eventPublisher.publishEvent(new LogoutSuccessEvent(authentication));
    }