SpringSecurity入門6---註銷登錄

代碼地址

實現

SpringSecurity爲我們實現了註銷的邏輯,修改配置即可實現註銷

@Override
    protected void configure(HttpSecurity http) throws Exception {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        http.authorizeRequests()
                .antMatchers("/css/**", "/img/**", "/js/**", "/bootstrap/**", "/captcha.jpg").permitAll()
                .antMatchers("/app/api/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin().loginPage("/myLogin.html")
                .loginProcessingUrl("/login")
                .successHandler(successHandler)
                .failureHandler(failureHandler)
                .authenticationDetailsSource(myWebAuthenticationDetailsSource)
                .permitAll()
                .and()
                .rememberMe().userDetailsService(userDetailsService()).tokenRepository(jdbcTokenRepository)
                //.rememberMe().userDetailsService(userDetailService).key("anntly")
                // 使登錄頁不受限
                .and()
                .csrf().disable()
                .logout()
                    // 註銷請求
                    .logoutUrl("/logout")
                    // 註銷後重定向路徑
                    .logoutSuccessUrl("/myLogin.html")
                    // 註銷成功後的處理,也可以在這裏重定向以及其他事情
                    .logoutSuccessHandler(new LogoutSuccessHandler() {
                        @Override
                        public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {

                        }
                    })
                    // 使用戶session失效
                    .invalidateHttpSession(true)
                    // 註銷後刪除指定的cookie
                    .deleteCookies("cookieDemo")
                    // 類似上面的logoutSuccessHandler,處理自定義邏輯
                    .addLogoutHandler(new LogoutHandler() {
                        @Override
                        public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {

                        }
                    });
    }

源碼解析

登出處理是由多個LogoutHandler實現的

public interface LogoutHandler {
	void logout(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication);
}

LogoutFilter中保存有一個聚合的LogoutHandler(CompositeLogoutHandler),在LogoutHandlerdoFilter方法中會調用CompositeLogoutHandler的logout方法來執行登出的邏輯

	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;

		if (requiresLogout(request, response)) {
			Authentication auth = SecurityContextHolder.getContext().getAuthentication();

			if (logger.isDebugEnabled()) {
				logger.debug("Logging out user '" + auth
						+ "' and transferring to logout destination");
			}
			// 登出
			this.handler.logout(request, response, auth);

			logoutSuccessHandler.onLogoutSuccess(request, response, auth);

			return;
		}

		chain.doFilter(request, response);
	}

	// CompositeLogoutHandler的logout方法,即遍歷執行
	public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
		for (LogoutHandler handler : this.logoutHandlers) {
			handler.logout(request, response, authentication);
		}
	}

我們的配置類實現了WebSecurityConfigurerAdapter,登出邏輯是由其注入的

protected final HttpSecurity getHttp() throws Exception {
        if (this.http != null) {
            return this.http;
        } else {
            DefaultAuthenticationEventPublisher eventPublisher = (DefaultAuthenticationEventPublisher)this.objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
            this.localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
            AuthenticationManager authenticationManager = this.authenticationManager();
            this.authenticationBuilder.parentAuthenticationManager(authenticationManager);
            this.authenticationBuilder.authenticationEventPublisher(eventPublisher);
            Map<Class<?>, Object> sharedObjects = this.createSharedObjects();
            this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);
            if (!this.disableDefaults) {
                ((HttpSecurity)((DefaultLoginPageConfigurer)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)this.http.csrf().and()).addFilter(new WebAsyncManagerIntegrationFilter()).exceptionHandling().and()).headers().and()).sessionManagement().and()).securityContext().and()).requestCache().and()).anonymous().and()).servletApi().and()).apply(new DefaultLoginPageConfigurer())).and()).logout(); // 登出邏輯
                ClassLoader classLoader = this.context.getClassLoader();
                List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
                Iterator var6 = defaultHttpConfigurers.iterator();

                while(var6.hasNext()) {
                    AbstractHttpConfigurer configurer = (AbstractHttpConfigurer)var6.next();
                    this.http.apply(configurer);
                }
            }

            this.configure(this.http);
            return this.http;
        }
    }

進入上面註釋的logout方法,是HttpSecurity的logout方法

public LogoutConfigurer<HttpSecurity> logout() throws Exception {
        return (LogoutConfigurer)this.getOrApply(new LogoutConfigurer());
    }

進入LogoutConfigurer,看到方法createLogoutFilter將logoutHandler注入了進去

private LogoutFilter createLogoutFilter(H http) {
        this.logoutHandlers.add(this.contextLogoutHandler);
        this.logoutHandlers.add(this.postProcess(new LogoutSuccessEventPublishingLogoutHandler()));
        LogoutHandler[] handlers = (LogoutHandler[])this.logoutHandlers.toArray(new LogoutHandler[0]);
        LogoutFilter result = new LogoutFilter(this.getLogoutSuccessHandler(), handlers);
        result.setLogoutRequestMatcher(this.getLogoutRequestMatcher(http));
        result = (LogoutFilter)this.postProcess(result);
        return result;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章