본문 바로가기

Spring/Security

Spring Security 9: Spring Session

개요

앞선 글을 보면 알겠지만 우리는 사용자의 정보를 세션에 저장하며 로그인을 하고 있다. 현재로서는 문제가 없겠지만, 사용자가 늘어나고 트래픽이 올라간다면 문제가 생길 것이다.

 

1. 서버 장애시 복제본이 없는 Session 정보는 유실 된다.

2. Session은 서버 메모리를 사용하기 때문에 너무 많아질 경우 서버 메모리 부족이 발생할 수 있다.

 

그림을 통해 이해해보자.

 

 

 

즉, Application Server중 한 곳이 장애가 났을 경우 로드 밸런서에 의해 가용성은 보장되지만, 해당 서버를 사용하던 사용자는 세션을 유실해서 로그아웃이 된다는 이야기다. 

 

 

Session Cluster

 

위 문제를 해결하기 위해 Session Cluster라는 것이 나오게 됐다. 이는 세션 정보를 외부 Storage에 따로 저장해서 서버가 장애가 나더라도 세션이 유지될 수 있도록 하는 개념이다.

 

 

Spring Session

 

Spring Session은 Session Cluster의 기능을 간단한 코드만을 작성해서 지원해주는 기술이다.

 

종류로는 spring-session-data-redis, spring-session-hazelcast, spring-session-data-mongodb, spring-session-jdbc가 있는데, 보통 메모리 기반으로 작동하는 redis를 많이 이용한다고 한다. (보통의 서비스에서 사용자의 정보로부터 많은 요청을 처리하는 데 성능이 중요한 부분이다. 따라서 메모리 기반으로 동작하는 redis를 많이 사용)

 

나의 경우 Redis에 대해 자세히 모르기 때문에 JDBC를 이용했다. (Redis는 추후 공부해보겠다.)

 

코드는 아래와 같다.

 

 

1. 의존성을 추가한다.

<dependency>
  <groupId>org.springframework.session</groupId>
  <artifactId>spring-session-jdbc</artifactId>
</dependency>

 

2. org.springframework.session.jdbc에 있는 session 관련 sql 파일이 있을텐데 해당 파일에 존재하는 스크립트를 실행한다. (필수는 아님)

 

 

아래 좀 잘렸지만 sql 파일이 db에 맞게 많이 있다.

 

3. yaml 파일 작성 2의 과정에서 schema 초기화를 해줬을 경우 never로 해도 되고 다른 옵션을 줘도 된다. (Always, embedded, never 가 있음)

 

spring:
  session:
      store-type: jdbc
      jdbc:
        initialize-schema: never

 

4. @EnableJdbcHttpSession 붙여주기

 

관심사의 분리를 원한다면 별도의 설정을 만들어서 해도 되지만 그것이 별로라면 아래처럼 main 클래스 위에 붙여도 된다.

 

@Configuration
@EnableJdbcHttpSession
public class HttpSessionConfig {

}

또는 

@SpringBootApplication
@EnableJdbcHttpSession
public class SsmcApplication {

    public static void main(String[] args) {
        SpringApplication.run(SsmcApplication.class, args);
    }

}

 

이제 적용이 완료됐다. 단일 서버에서 테스트를 하려면 session cluster의 스키마를 초기화 하지 않고, 어플리케이션을 종료했다 다시 켰을 때 로그인이 그대로 되어 있을 것이다.

 

 

동작 과정

  • Spring Session의 SessionRepositoryFilter 클래스는 Spring Security의 DelegatingFilterProxy 보다 먼저 실행된다.
  • Spring Security의 SecurityContextPersistenceFilter는(Spring Security 6 버전 이후 deprecated 됨) SecurityContextHolderFilter는 SecurityContextRepository 인터페이스 구현체를 통해 사용자의 SecurityContext를 가져오거나 갱신한다.
    • SecurityContextRepository 인터페이스 기본 구현은 Session을 이용하는 HttpSessionSecurityContextRepository 클래스
    • HttpServletRequest 인터페이스의 getSession() 메소드를 통해 Session을 가져옴
      • 바로 이 지점에서 HttpServletRequest 인터페이스의 스프링 세션 구현체인 SessionRepositoryRequestWrapper 클래스가 사용