Spring Boot와 Redis 간단하게 연동하기

wisdom·2022년 8월 18일
2

Spring Boot

목록 보기
5/7
post-thumbnail

JWT 인증 방식에서, access token이나 refresh token을 유효 기간만큼만 Redis에 저장하여 사용하는 경우가 많다.

다음 두 가지를 만족하도록 구현할 것이다.
1. 토큰을 Redis에 저장하고, 유효 기간만큼 TTL(Time To Live)을 지정하기
2. 로그인할 때는 토큰을 Redis에 저장하고, 로그아웃할 때는 저장된 토큰을 삭제하기

Redis 연동에 관한 것 위주로만 다루고, 인증 관련 로직은 모두 생략할 것이다!

1. Docker로 Redis 실행

먼저 redis 서버를 실행시킨다. (redis_version 7.0.0)

직접 redis 서버를 설치해서 실행해도 되지만, docker를 사용해서 실행하였다.

$ docker run -d -p 6379:6379 redis

💡 redis-cli 실행 방법

$ docker exec -it [컨테이너 id] redis-cli
  • 컨테이너 id : 위에서 실행시킨 redis 컨테이너의 id

2. Spring boot에서 Redis 설정

의존성 추가

implementation 'org.springframework.boot:spring-boot-starter-data-redis'

application-redis.properties 파일

spring.redis.host=127.0.0.1
spring.redis.port=6379

🔖  redis의 기본 포트는 6379번이다.

spring boot 2.0 이상부터는 auto-configuration으로 빈(redisConnectionFactory, RedisTemplate, StringTemplate)들이 자동으로 생성되기 때문에 위와 같이 properties 파일(혹은 yml 파일)에 설정만 해주면 된다!


3. Token을 위한 Entity와 Repository 생성

import lombok.Builder;
import lombok.Getter;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;

@Getter
@RedisHash("token")
public class Token {
    @Id
    Long user_id; // 회원의 id

    String token; // 토큰 값

	@TimeToLive
    Integer expiration;

    @Builder
    public SocialToken(Long user_id, String token, Integer expiration) {
        this.user_id = user_id;
        this.token = token;
        this.expiration = expiration;
    }
}
  • @RedisHash : Redis의 Hash 자료구조(Key-Value Map). JPA의 @Entity 에 해당하는 애노테이션이라고 할 수 있다. 애노테이션의 value 값은 Key의 prefix가 된다.
    • Hash의 Key는 value:@Id 형태로 형성된다. (여기서는 value:{user_id})
    • Hash의 Value에는 모든 필드값과 클래스 이름이 저장된다.
    • 애노테이션의 value 값으로 Redis의 Set 자료구조가 생성되며, 그 안에는 @Id 값들이 저장된다.
  • @Id : key를 식별할 때 사용하는 고유한 값. @RedisHash와 결합해서 key를 생성한다.
  • @Indexed : CRUD Repository를 사용할 때 jpa의 findBy필드명 처럼 사용하기 위해서 필요한 애노테이션.
  • @TimeToLive : 유효시간(초 단위). 유효 시간이 지나면 자동으로 삭제된다.
    • @TimeToLive(unit = TimeUnit.MILLISECONDS) 옵션으로 단위를 변경할 수 있다.

import org.springframework.data.repository.CrudRepository;

public interface TokenRedisRepository extends CrudRepository<Token, Long> {
}
  • JpaRepository 사용법과 매우 유사하다.
  • CrudRepository를 상속받아 기본적으로 save(), findById(), findAll(), delete() 등의 메소드를 사용할 수 있다.
  • @Id가 아닌 값을 findBy로 조회하고 싶을 경우, @Indexed 애노테이션을 필드에 붙이고 findBy… 메소드를 여기에 선언하면 된다.

4. Token 저장 / 조회 / 삭제

RedisService


import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Slf4j
public class RedisService {

		private final TokenRedisRepository tokenRedisRepository;
	
		// 토큰 저장
		@Transactional
		public void saveToken(Long userId, TokenResponse token) {
		    try {
		        tokenRedisRepository.save(SocialToken.builder()
		                .user_id(userId)
		                .token(token.getAccessToken())
										.expiration(token.getExpiresIn())
		                .build());
		    } catch (Exception e) {
		        log.error(e.getMessage());
		    }
		}

		// 토큰 조회
		public String getToken(Long userId) {
            try {
                return tokenRedisRepository.findById(userId)
                        .orElseThrow(IllegalArgumentException::new) // 토큰이 존재하지 않은 경우
                        .getToken();
            } catch (Exception e) {
                  log.error(e.getMessage());
            }
        }

		// 토큰 삭제
        @Transactional
        public void deleteToken(Token token) {
        	try {
                tokenRedisRepository.delete(token);
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }

}

TokenResponse

  • 토큰 정보를 저장할 클래스
  • Oauth2 인증을 사용할 경우, 로그인 성공 시 여기에 토큰 정보를 저장한다.
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

@NoArgsConstructor
@Getter
@ToString
public class TokenResponse {

    @JsonProperty("token_type")
    String tokenType;

    @JsonProperty("access_token")
    String accessToken;

    @JsonProperty("refresh_token")
    String refreshToken;

    @JsonProperty("expires_in")
    Integer expiresIn;

    @JsonProperty("refresh_token_expires_in")
    Integer refreshTokenExpiresIn;

    String scope;
}

5. 로그인 / 로그아웃

로그인 시에는 발급받은 토큰을 Redis에 저장한다.

// 회원 ID과 token을 받아오는 로직 (생략)
// 로그인 로직 (생략)

redisService.saveSocialToken(userId, token);

로그아웃 시에는 토큰을 삭제한다.

// 회원 ID를 받아오는 로직 (생략)
// 로그아웃 로직 (생략)

Token token = redisService.getToken(userId);
redisService.deleteToken(token);



🔖 참조
https://bcp0109.tistory.com/328
https://backtony.github.io/spring/redis/2021-08-29-spring-redis-1/

profile
백엔드 개발자

0개의 댓글