实现
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;
}