實現
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),在LogoutHandler
的doFilter
方法中會調用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;
}