조건
- 시스템은 중복 로그인이 2회까지 가능합니다.
- Api pod 는 2개가 실행중입니다.
실패 시나리오
1. Pod A 에 test@com 계정이 로그인을 시도했고 성공했습니다.
2. Pod A 에 test@com 계정이 로그인을 시도했고 성공했습니다.
( 이 때 까지는 중복 로그인이 허용되는 범위입니다. )
3. Pod B 에 test@com 계정이 로그인을 시도했고 중복 로그인이 허용되는 범위를 초과했습니다.
( 하지만 로그인 성공했습니다. )
이슈
Redis 에서 통합적인 session 관리를 하므로 Pod B 에서 시도한 3회차 로그인 시도에서는 중복로그인이 허용되는 범위를 초과했기 때문에 중복 로그인이 실패해야합니다.
Pod 2 에서 로그인된 계정을 판단할 때 Pod 1 에 있는 두 개의 계정에 대한 인식을 못하고 있습니다.
Spring Redis Session 설정을 완료했음에도 불구하고 Spring Security 에서 사용하는 SessionRegistry 는 아직 Spring Session 에서 관리되고 있는 듯합니다.
해결 방안
아래와 같이 @EnableRedisHttpSession 선언을 해준 후 SessionRepository 를 Bean 으로 등록할 때 Redis 를 사용하겠다고 선언하면 됩니다.
@EnableRedisHttpSession
public class RedisSessionConfiguration {
@Bean
public SessionRegistry springSessionBackedSessionRegistry(RedisIndexedSessionRepository redisIndexedSessionRepository) {
return new SpringSessionBackedSessionRegistry<>(redisIndexedSessionRepository);
}
}
그럼 아래와 같이 SessionRepository 를 통해서 중복 로그인 체크를 Redis 에서 관리하기 때문에 Pod 간의 Security Session Storage 가 통합되지 않아 발생하는 문제는 해결이 됩니다.
private final SessionRegistry sessionRegistry;
public Authentication authenticate(Authentication auth) {
...
/** 중복로그인 체크 **/
List<SessionInformation> allSessions = sessionRegistry.getAllSessions(userDetails.getUsername(), false);
int sessionSize = allSessions.size();
if (company.getDuplicateLoginCnt() - sessionSize == 0) {
throw new CustomAuthenticationException(ExceptionType.EXCEED_DUPLICATION_LOGIN);
}
...
}
너무나 당연히 SecurityFilterChain 에 sessionRegistory 는 설정해줘야합니다.
private SessionRegistry sessionRegistry;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
...
http.sessionManagement()
.maximumSessions(1)
.sessionRegistry(sessionRegistry);
...
}