redis를 통해 로그아웃 기능 구현
Redis
Redis
는 오픈 소스 기반의 비관계형 DBMS로, Key-Value
구조의 비정형 데이터를 저장하고 관리한다. 이는 우리가 흔히 사용하는 MySQL
과는 다르게, 인메모리 데이터 구조를 가진 저장소이다.
MySQL
과 같은 전통적인 DB는 데이터를 디스크에 저장한다. 이로 인해 서버가 다운되더라도 데이터는 보존되지만, 데이터를 조회할 때 디스크에서 읽어야 하므로 속도 면에서 불리하다. 반면, Redis
는 자주 사용되는 데이터를 메모리에 저장하여 빠른 데이터 접근 속도를 제공한다.
따라서 이번 프로젝트에서는 Redis
를 활용하여 사용자의 로그아웃 시 발급된 JWT 토큰을 저장하고, 이를 BlackLis
t로 관리한고, JWT 토큰의 유효 시간 동안 해당 토큰을 Redis
에 보관함으로써, 로그아웃 후 토큰이 탈취되더라도 해당 토큰을 악용할 수 없게 했다.
1. Docker를 통해 Redis 실행하기
docker pull 을 사용하여 Redis 이미지 다운받기
docker pull redis
pull 받은 이미지로 docker Container 실행하기
sudo docker run -d --name redis -p 6379:6379 redis
여기까지 성공했다면
docker ps -a
명령어를 통해 실행중인 컨테이너에 아래와같이 redis를 실행하는 컨테이너가 생길것이다.
2. yml 파일 작성하기
본 프로젝트는 profile
을 사용하여 각 환경에 필요한 yml
파일을 읽게한다.
application.yml
파일은 아래와 같다.
spring:
profiles:
group:
local: localDB, jasypt, oauth, mybatis, aws, redis
prod: prodDB, jasypt, oauth, mybatis, aws, redis
test: testDB, jasypt, oauth, mybatis, aws, redis
active: local
application-redis.yml
에 아래와 같은 정보를 저장한다.
redis:
pool:
min-idle: 0
max-idle: 8
max-active: 8
port: 6379
host: 127.0.0.1 // spring boot 는 따로 container로 실행하지 않았을때
만약 spring 서버도 독립적인 container에서 실행되고 있다면 docker-compose 에서 host 이름을 지정해준다음 위 yml
파일 host에 지정해준 이름을 넣어주면 된다.
3. RedisProperties 클래스를 정의
@Component
@ConfigurationProperties(prefix = "redis")
@Getter
@Setter
public class RedisProperties {
private int port;
private String host;
}
해당 클래스를 통해 우리가 yml에서 지정해준 port 및 host 정보를 가져온다.
@ConfigurationProperties
를 사용하면 application-redis.yml
에 정의한 redis.host
와 redis.port
설정 정보를 가져와 RedisProperties
에 바인딩 한다.
4. RedisConfig 를 정의한다.
@RequiredArgsConstructor
@Configuration
@EnableRedisRepositories
public class RedisConfig {
private final RedisProperties redisProperties;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisProperties.getHost(), redisProperties.getPort());
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
return redisTemplate;
}
}
RedisConfig
클래스를 통해 우리가 원하는 Redis
의 설정정보를 구성해준다. 여기서 설정해준 정보를 통해 Redis
와의 연결 및 데이터 처리방식을 제공한다.
@EnableRedisRepositories
: Redis를 사용한 데이터 접근을 위해 Spring Data Redis 리포지토리를 활성화한다.redisConnectionFactory()
: Redis와의 연결을 위한ConnectionFactory
를 생성한다. 여기서는 Lettuce 라이브러리를 사용하여 연결을 생성한다.redisTemplate()
: Redis 데이터 작업을 위한 중심적인 클래스인RedisTemplate
을 정의한다. 이 메서드에서는 키와 값의 직렬화 방식을StringRedisSerializer
로 설정했다.LettuceConnectionFactory
: Lettuce는 Redis 클라이언트 중 하나로, 비동기 이벤트 기반의 연결을 제공한다. 여기서는RedisProperties
에서 제공하는 호스트와 포트 정보를 사용하여 연결을 생성한다.StringRedisSerializer
: 이 직렬화 방식은 Redis의 키와 값으로 문자열을 사용하려는 경우에 사용한다.
RedisConnectionFactory
역할:
RedisConnectionFactory
는 Redis 서버와의 연결을 관리하는 인터페이스다. 이 인터페이스를 구현한 클래스는 Redis 서버와의 연결 세션을 생성하고 관리한다.Lettuce 라이브러리:
- Lettuce는 Redis 클라이언트 중 하나로, 네티(Netty) 기반의 비동기 이벤트 구동 모델을 사용한다.
- 여러 Redis 노드 구성(예: Sentinel, Cluster)을 지원하며, 연결 풀링이 내장되어 있어 고성능 환경에서도 잘 동작한다.
LettuceConnectionFactory
는 Lettuce 클라이언트를 사용하여 Redis 서버와의 연결을 생성하고 관리한다.
RedisTemplate
역할:
RedisTemplate
는 Redis와의 데이터 작업을 추상화하여 제공하는 헬퍼 클래스이다. Redis의 데이터 구조와 명령을 Java 객체와 메서드로 매핑하여, Java에서 Redis 작업을 쉽게 수행할 수 있게 해준다.직렬화:
- Redis는 바이트 배열 형태로 데이터를 저장한다. 따라서 Java 객체를 Redis에 저장하거나 조회할 때는 객체를 바이트 배열로 변환하거나 바이트 배열을 객체로 변환하는 작업이 필요하며, 이러한 작업을 직렬화(Serialization) 및 역직렬화(Deserialization)라고 한다.
RedisTemplate
에서는 키와 값의 직렬화 방식을 설정할 수 있다. 예를 들어,StringRedisSerializer
는 문자열 데이터를 바이트 배열로 변환하는 직렬화 방식이다.
활용:
RedisTemplate
를 사용하면, Redis의 기본 데이터 구조(예: String, List, Set, Hash, ZSet)에 대한 연산을 Java 메서드로 쉽게 수행할 수 있다. 또한, 트랜잭션, 파이프라인, 스크립트 실행 등의 고급 기능도 지원한다.
5. Redis Util 정의
최종적으로 RedisUtil
이라는 클래스를 통해 특정 메서드를 사용하여 Redis
에 작업을 할수있게하는 클래스를 정의해준다.
@Component
@RequiredArgsConstructor
public class RedisUtil {
private final RedisTemplate<String, Object> redisBlackListTemplate;
public void setBlackList(String key, Object o, int minutes) {
//Redis에 저장할 데이터 방식을 설정
redisBlackListTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(o.getClass()));
//Redis의 String타입 구조에 작업을 수행하기 위한 연산
redisBlackListTemplate.opsForValue().set(key, o, minutes, TimeUnit.MINUTES);
}
public boolean hasKeyBlackList(String key) {
return Boolean.TRUE.equals(redisBlackListTemplate.hasKey(key));
}
}
여기까지 했다면, RedisUtil 클래스의 setBlackList
메서드를 통해 우리가 원하는 토큰을 지정해준 시간이 지날때까지 Redis
에 보관을 하며, Redis
에 존재하는 JWT
토큰으로 로그인을 한 상태를 유지할수 없게 만든다.
setBlackList 메서드:
Jackson2JsonRedisSerializer
: Jackson 라이브러리를 사용하여 Java 객체를 JSON 형식으로 직렬화하거나 JSON을 Java 객체로 역직렬화하는 직렬화 방식이다. 여기서는 저장하려는 객체의 클래스 타입을 기반으로 직렬화 방식을 설정하고 있다.opsForValue().set(key, o, minutes, TimeUnit.MINUTES)
: Redis의 String 데이터 구조에 값을 저장하는 메서드이다. 지정된 키, 값, 만료 시간, 시간 단위를 사용하여 데이터를 저장한다.
- hasKeyBlackList 메서드: 지정된 키가 Redis에 존재하는지 확인하는 메서드이다.
Boolean.TRUE.equals()
를 사용하여 결과가true
인지 확인하고 있다.
6. Redis 내부 데이터 확인하기
Redis
를 실행중인Container
내부에 들어가기docker exec -it redis /bin/bash
Redis
에 접속하기redis-cli
Redis
에 저장된key
확인하기keys *
특정
key
에대한 만료시간 확인하기ttl <key>
위 명령어를 통해 redis에 저장된 토큰을 확인할수 있으며, 해당 토큰을 통해 로그인을 하려할때 filter
를 통해 로그인을 막을수 있다.
'Spring' 카테고리의 다른 글
[Spring] Enum 타입으로 Exception 구현하기 (0) | 2024.07.22 |
---|---|
docker hub 사용하는 방법 (1) | 2023.11.27 |
Jasypt 를 통한 암호화 (2) | 2023.11.27 |
checkedException, uncheckedException (1) | 2023.11.22 |
Transactional을 통한 rollback시 AUTO_INCREMENT 초기화 문제 (0) | 2023.07.06 |