반응형
Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | 30 | 31 |
Tags
- 정규식
- 자바문법
- 인텔리제이
- 문자열
- Array
- junit
- 자바
- string
- js
- Visual Studio Code
- Java
- 스프링부트
- 테스트자동화
- HashMap
- html
- javascript
- 단위테스트
- math
- CSS
- vscode
- list
- java테스트
- input
- junit5
- Eclipse
- ArrayList
- SpringBoot
- IntelliJ
- 자바스크립트
- 배열
Archives
- Today
- Total
어제 오늘 내일
[Spring Security] 12편 - Redis 도입 & TTL로 토큰 자동 삭제하기 본문
지난 시간엔 DB에 Refresh Token을 저장했습니다.
하지만 만료된 토큰이 DB에 계속 쌓이는 문제가 있죠.
이를 해결하기 위해 "시간이 지나면 알아서 사라지는" Redis를 도입해 보겠습니다.
Step 0. Redis 준비
로컬에 Redis가 설치되어 있어야 합니다. (Docker 사용 추천)
docker run -p 6379:6379 --name my-redis -d redis
Step 1. 의존성 추가 (build.gradle)
JPA 대신 Redis를 사용하기 위한 라이브러리를 추가합니다.
dependencies {
// ... 기존 의존성 ...
// Spring Data Redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
}
Step 2. Redis 설정 (application.yml)
스프링 부트와 Redis를 연결합니다.
spring:
data:
redis:
host: localhost
port: 6379
Step 3. Entity 수정 (@RedisHash 적용)
기존의 @Entity(JPA)를 지우고, Redis용 어노테이션인 @RedisHash로 변경합니다.
여기가 TTL 설정의 핵심입니다!
- 위치:
src/main/java/com/example/board/domain/entity/RefreshToken.java
package com.example.board.domain.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
// value: Redis의 키 prefix (예: refreshToken:silver)
// timeToLive: 만료 시간 (초 단위). 604800초 = 7일
@RedisHash(value = "refreshToken", timeToLive = 604800)
@AllArgsConstructor
@Getter
public class RefreshToken {
@Id
private String id; // userId (username)
private String refreshToken;
// RTR: 토큰 교체 메서드
public void updateRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
}
💡 변경점 분석
@RedisHash: JPA의@Entity대신 사용합니다.timeToLive = 604800: [핵심] 이 객체는 Redis에 저장된 후 7일(604,800초)이 지나면 자동으로 삭제됩니다. 더 이상 DB 배치를 돌려 삭제할 필요가 없습니다!@Id:jakarta.persistence.Id가 아니라org.springframework.data.annotation.Id를 임포트해야 합니다.
Step 4. Repository 수정 (CrudRepository)
JpaRepository 대신 Redis를 지원하는 CrudRepository를 상속받습니다. 사용법은 거의 똑같습니다.
- 위치:
src/main/java/com/example/board/domain/repository/RefreshTokenRepository.java
package com.example.board.domain.repository;
import com.example.board.domain.entity.RefreshToken;
import org.springframework.data.repository.CrudRepository;
import java.util.Optional;
public interface RefreshTokenRepository extends CrudRepository<RefreshToken, String> {
// CrudRepository가 기본적으로 findById를 제공하므로
// 별도의 메소드 정의가 없어도 됩니다.
}
Step 5. Service 로직 수정
로직 흐름은 같지만, 저장 방식이 Redis로 바뀌면서 메소드 이름이 미세하게 바뀔 수 있습니다. (JPA findByKey -> Redis findById)
- 위치:
src/main/java/com/example/board/service/MemberService.java
// ... (기존 코드) ...
@Transactional
public JwtToken login(String username, String password) {
// ... (인증 및 토큰 생성 로직 동일) ...
// 4. Refresh Token 저장 (Redis)
RefreshToken refreshToken = new RefreshToken(authentication.getName(), jwtToken.getRefreshToken());
refreshTokenRepository.save(refreshToken); // Redis에 저장 & TTL 자동 설정됨
return jwtToken;
}
@Transactional
public JwtToken reissue(String refreshToken) {
// ... (검증 로직 동일) ...
// 3. Redis에서 User ID를 기반으로 저장된 Refresh Token 값을 가져옵니다.
RefreshToken redisToken = refreshTokenRepository.findById(authentication.getName())
.orElseThrow(() -> new RuntimeException("로그아웃 된 사용자입니다.")); // Redis에 없으면 만료된 것임
// 4. 토큰 일치 검사
if (!redisToken.getRefreshToken().equals(refreshToken)) {
throw new RuntimeException("토큰의 유저 정보가 일치하지 않습니다.");
}
// 5. 새 토큰 생성
JwtToken newJwtToken = jwtTokenProvider.createToken(authentication);
// 6. Redis 업데이트 (Dirty Checking이 안되므로 save를 다시 호출해야 함)
// RedisRepository는 JPA처럼 변경감지가 안 될 수 있으므로, 명시적으로 save나 update를 해줍니다.
redisToken.updateRefreshToken(newJwtToken.getRefreshToken());
refreshTokenRepository.save(redisToken);
return newJwtToken;
}
💡 Redis 적용 결과 확인
이제 코드를 실행하고 로그인을 해봅시다. 그리고 redis-cli나 GUI 툴로 확인해보면:
> keys *
1) "refreshToken:silver" <-- 이렇게 저장됨
> ttl refreshToken:silver
(integer) 604795 <-- 남은 시간이 초 단위로 뜸 (점점 줄어듦)
Access Token이 만료되어 재발급 요청을 하면?
- Redis에서 토큰을 찾아 검증하고,
- 새 토큰을 발급해주면서 Redis 값도 갱신(Rotation)되고,
- TTL도 다시 7일로 초기화됩니다. (로그인 연장 효과)
🎉 마무리
이제 여러분의 프로젝트는:
- DB 부하 감소: 잦은 토큰 조회/저장을 빠른 Redis가 처리합니다.
- 자동 관리: 7일이 지나면 Redis가 알아서 토큰을 지워주므로, 로그아웃 된 유저 데이터가 쌓이지 않습니다.
반응형
'IT > SpringBoot' 카테고리의 다른 글
| [Spring Security] 14편 - 필터 예외 처리의 정석 (ExceptionHandlerFilter) (0) | 2026.02.24 |
|---|---|
| [Spring Security] 13편 - 예외 처리 (401/403 예쁘게 응답하기) (0) | 2026.02.24 |
| [Spring Security] 11편 - 로그아웃은 싫어! 리프레시 토큰(Refresh Token) 완벽 구현하기 (1) | 2026.02.23 |
| [Spring Security] 10편 - 한눈에 보는 JWT 동작 원리 (Sequence Diagram & 총정리) (0) | 2026.02.21 |
| [Spring Security] 9편 - JWT 로그인 API 구현 & Postman 테스트 (0) | 2026.02.20 |
Comments
