我正在开发一个没有Spring Security 4.0.0的Java Config而不是xml配置的Web应用程序。我使用ObjectPostProcessor
来自定义一些Spring Security的bean,特别是会话并发的bean(一旦用户再次登录就立即使会话失效,而不是Spring在下次请求时失效的标准行为)。
它在大多数时候都按预期工作,但有时当我重新启动应用程序时,似乎并非所有bean都按我的意愿进行修改。
SecurityBuilder
是按特定顺序处理还是以ramdom顺序处理?
编辑:
@EnableWebSecurity
public class SecurityConfig extends AbstractCASWebSecurityConfigurerAdapter {
public SecurityConfig() {
super(true, false, true);
}
@Autowired
private Environment env;
// we need a custom SessionRegistry as there's no way to get ahold of the one created by the configurer.
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
// we need a custom HttpSessionCsrfTokenRepository as there's no way to get ahold of the one created by the configurer.
@Bean
public CsrfTokenRepository csrfTokenRepository() {
return new HttpSessionCsrfTokenRepository();
}
// our custom ConcurrentSessionControlAuthenticationStrategy that invalidates session immediately
@Bean
public SessionInvalidatingConcurrentSessionControlAuthenticationStrategy myConcurrentSessionControlAuthenticationListener()
{
// we have to recreate the LogoutHandlers because we need to call them
// before invalidating the session
final LogoutHandler [] logoutHandlers = new LogoutHandler [] {
new CookieClearingLogoutHandler("JSESSIONID"),
new CsrfLogoutHandler(csrfTokenRepository())
//, new SecurityContextLogoutHandler() // seems to create problems with redirecting to the same page that caused the login request
};
SessionInvalidatingConcurrentSessionControlAuthenticationStrategy mine = new SessionInvalidatingConcurrentSessionControlAuthenticationStrategy(sessionRegistry(), logoutHandlers);
mine.setExceptionIfMaximumExceeded(false);
mine.setMaximumSessions(1);
return mine;
}
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
boolean devMode = this.env.acceptsProfiles("development");
final String [] ignoredPaths = devMode
? new String [] {"/webjars/**", "/static/**", "/bower_components/**" }
: new String [] {"/webjars/**", "/static/**" };
web
.ignoring()
.antMatchers(ignoredPaths)
.and()
.debug(false)
;
}
protected void configure(final HttpSecurity http) throws Exception {
super.configure(http);
http
.sessionManagement()
.maximumSessions(73467436) // this is just to trigger the ConcurrencyControlConfigurer
.sessionRegistry(sessionRegistry())
.and()
.withObjectPostProcessor(new ObjectPostProcessor<ConcurrentSessionControlAuthenticationStrategy>() {
@SuppressWarnings("unchecked")
@Override
public <O extends ConcurrentSessionControlAuthenticationStrategy> O postProcess(O concurrentSessionControlAS) {
// substitute the ConcurrentSessionControlAuthenticationStrategy created by
// ConcurrencyControlConfigurer with our own
return (O) myConcurrentSessionControlAuthenticationListener();
}
})
.and()
// we need to ignore the stomp endpoint to allow SockJS javascript client to issue POST requests
// to /push/../../.. when using trasports which are not WebSocket;
// at that time, protection is given by Stomp CSRF headers
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.ignoringAntMatchers("/push/**")
.and()
// allow same origin to frame our site to support iframe SockJS
.headers()
.frameOptions().sameOrigin()
.and()
.authorizeRequests()
.antMatchers("/help/**").permitAll() // help redirects do not require authentication
.antMatchers("/push/info").permitAll() // do not require being authenticated for the /info request by SockJS
.anyRequest().authenticated()
.and()
// remove the session cookie when logging out
.logout()
.deleteCookies("JSESSIONID") // see: http://docs.spring.io/autorepo/docs/spring-security/current/reference/htmlsingle/#detecting-timeouts
.and()
;
}
}
AbstractCASWebSecurityConfigurerAdapter
是一个配置CAS的AbstractWebSecurityConfigurerAdapter。