目前我们有一个spring-security成功运行的spring-boot(1.2.1.RELEASE)应用程序。
我们已经成功实现了并发控制,配置如下
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig {
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@Configuration
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
private static final int MAX_CONCURRENT_USER_SESSIONS = 1;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//snipped
.sessionManagement()
.maximumSessions(MAX_CONCURRENT_USER_SESSIONS)
.maxSessionsPreventsLogin(true)
.sessionRegistry(sessionRegistry());
}
@Bean
public SessionRegistry sessionRegistry() {
SessionRegistry sessionRegistry = new SessionRegistryImpl();
return sessionRegistry;
}
@Bean
public static HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
}
}
如果您尝试在 2 个不同的会话中使用相同的用户帐户登录,则第二次尝试将失败,直到当前用户按预期和要求注销。
这在单实例环境中效果很好,但我们希望部署到 Herkou 上的多个 dyno,因此需要外部化会话。
spring-session + spring-boot-starter-redis 似乎是一个很好的候选人。
从 spring-session 文档中,它提到我们需要做的就是添加注释@EnableRedisHttpSession
并定义一个JedisConnectionFactory
.
这确实有效,并且添加该注释会导致会话存储在 Redis 中,我可以使用 redis-cli 看到。
但是,添加此注释会破坏并发控制。
@EnableRedisHttpSession
添加注释后,SessionRegistryImpl
永远不会调用方法,也不会调用HttpSessionEventPublisher.sessionCreated()/sessionDestroy()
方法。
这意味着当当前用户注销时,尝试使用该用户名的其他会话仍然无法登录,并且刚刚注销的用户将无法重新登录。这是因为会话永远不会从 ???registry/repository??? 中删除
任何关于如何让我的会话创建/销毁工作的见解,同时使用 redis 作为存储,将不胜感激。