로드밸런서(L4)를 이용한 Scale-out된 분산 환경에서는 세션 불일치의 문제가 발생함
그러나 특정 서버로만 요청을 하기 때문에 문제점이 존재한다.


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
spring:
session:
store-type: redis
redis:
namespace: spring:session # 기본값
data:
redis:
host: localhost
password: 1234
port: 6379
Spring Session을 활성화하고 Redis를 세션 저장소로 설정하는 클래스
@Configuration
public class SessionConfig {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("JSESSIONID"); // 세션 쿠키 이름
serializer.setCookiePath("/"); // 세션 쿠키 경로
serializer.setDomainNamePattern("^.+?(\\w+\\.[a-z]+)$"); // 서브 도메인에 세션 쿠키 공유
serializer.setUseBase64Encoding(true); // Base64 인코딩 사용 유무 (false 시 세션ID를 단순 문자열로 처리)
return serializer;
}
}
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Base64;
@Slf4j
@Component
@RequiredArgsConstructor
public class AuthInterceptor implements HandlerInterceptor {
private static final String SESSION_KEY = "SESSION";
private static final String REDIS_SESSION_KEY = ":sessions:";
@Value("${spring.session.redis.namespace}")
private String namespace;
private final StringRedisTemplate redisTemplate;
@Override
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) throws Exception {
final String sessionIdByCookie = getSessionIdByCookie(request);
if (sessionIdByCookie != null) {
final String decodedSessionId = new String(Base64.getDecoder().decode(sessionIdByCookie)); // Base64 인코딩 false 시 코드 제거
// Redis에서 세션 키 확인. 존재하지 않으면 예외 발생
if (!redisTemplate.hasKey(namespace + REDIS_SESSION_KEY + decodedSessionId)) {
log.warn("Session Cookie exists, but Session in Storage does not exist");
throw new AuthException.FailAuthenticationMemberException();
}
}
return true;
}
private String getSessionIdByCookie(HttpServletRequest request) {
if (request.getCookies() != null) {
for (var cookie : request.getCookies()) {
if (cookie.getName().equals("JSESSIONID")) {
return cookie.getValue();
}
}
}
return null;
}
}