Spring

[Spring] Redis 기반 세션 스토리지 구축 (2)- 구현

J_Dev 2024. 11. 1. 15:05

Spring 코드 구현

  • 기존의 JDBC와 결합된 코드에서 세션 관리 부분만 Redis로 변경하여 간편하게 Session Storage를 변경하였다.
  • 특히 Spring Security 와 통합이 간편하여, 별다른 설정없이 구현이 가능했다.

1. build.gradle

  • 라이브러리를 추가해준다.
  • 상단은 Redis 연결을 위한 라이브러리, 하단은 Redis를 session storage로 쓰기위한 라이브러리다.
    //Redis
    implementation 'org.springframework.boot:spring-boot-starter-data-redis' 
    //Spring Session Library for Redis 
    implementation 'org.springframework.session:spring-session-data-redis'`
    

2. application.porperties

  • Redis 서버와 연결하기 위한 환경변수를 설정한다.
  • Docker Compose로 실행할 예정이므로, 환경 변수로 Redis 서버 호스트를 설정하였다.
# Redis Session Storage
spring.session.store-type=redis
spring.session.redis.host=${REDIS_SESSION_HOST}
spring.session.redis.port=6379

#session limit time
spring.session.timeout=5m

3. Redis Config Class

  • Redis 서버와 연결하기 위한 Bean 객체를 생성한다.
  • @EnableRedisHttpSession 어노테이션을 사용하여 HTTP Session을 자동으로 Redis에 저장, 관리한다.
  • hostprot@Value 로 환경변수에 저장하여 propertiy binding 하여 안전하게 관리했다.
  • Spring Session이 자동 직렬화 기능을 제공하기 때문에 별도의 RedisTemplate 설정 없이 세션을 Redis에 저장할 수 있다.(캐시로 사용시 필요)
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

@Configuration
@EnableRedisHttpSession
public class RedisSessionConfig {

    @Value("${spring.session.redis.host}")
    private String host;

    @Value("${spring.session.redis.port}")
    private int port;

    @Bean
    @Primary
    public RedisConnectionFactory redisSessionConnectionFactory() {
        RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
        configuration.setHostName(host);//host 할당
        configuration.setPort(port);//port 할당(기본값 6379)
        return new LettuceConnectionFactory(configuration);//redis 연결을 위한 Connection Factory 생성 Bean 으로 관리
    }

4. RESTful API

  • 기존의 API는 Spring Security와 결합되어 있어 인증 정보가 필요할 때 Authentication 객체를 사용해 유저 정보를 확인하였다.
  • 세션 정보 저장시 SecurityContext 도 Redis에 함께 저장되므로 다른 WAS 인스턴스에서도 유저정보에 쉽게 접근, 조회 할 수 있다.
...나머지코드생략
   @GetMapping("/members/me/mypage")
    @ResponseBody
    public ResponseEntity<MemberMyPageDto> showMyPage(
            Authentication authentication) {
        //유저 인증 정보가 없으면 badRequest 응답, 정보가 있으면  CustomOAuth2User로 타입캐스팅
        CustomOAuth2User principal = authenticator.checkAuthenticate(authentication);
        //유저 정보 DB에서 찾아 반환, 닉네임, 코인갯수, 이메일 정보 포함
        MemberMyPageDto memberMyPageInfo = memberService.getMemberMyPageInfo(principal.getName());
        //유저 정보 전
        return ResponseEntity.ok(memberMyPageInfo);
    }

5. docker-compose.yml

  • Docker Compose를 사용해 여러 WAS와 Redis를 연결하였다.
  • 서비스가 app-network라는 네트워크를 통해 서로 통신한다.
version: '3.8'
services:
  backend:
    build:
      context: ./netnovel
      dockerfile: Dockerfile
    container_name: backend

    ports:
      - "8081:8081"                    # 애플리케이션 포트 설정
    environment:
      - SPRING_PROFILES_ACTIVE=prod  # 프로덕션 프로파일 활성화
      - DB_URL=jdbc:mysql://172.27.32.1:3306/netnovel
      - DB_USERNAME=            
      - DB_PASSWORD=

      - REDIS_SESSION_HOST= redis-session # Redis 호스트 이름 설정
    networks:
      - app-network

  redis-session:
    image: redis:alpine                      # Redis 이미지
    container_name: redis-session
    ports:
      - "6379:6379"                          # Redis 포트 노출
    networks:
      - app-network

networks:
  app-network:
    driver: bridge                   # 각 컨테이너가 통신할 네트워크 설정 bridege 모드는 Docker 기본 네트워크 모드

6. 실행 및 테스트

로그인 테스트

  • 정상적으로 로그인이 완료되고 SESSION ID또 발급된것을 확인할 수 있다.

  • Redis Insight로 확인하면 다음과 같이 저장된 것을 확인할 수 있다.

결론

  • Spring Session과 Redis를 결합하여 간단하게 Redis 기반의 세션 스토리지를 구현할 수 있었다.
  • Spring Session과 Spring Security는 자동으로 결합되기 때문에,보안 설정을 수정할 필요 없이 Redis로 세션 스토리지를 전환할 수 있었다.