Skip to content

Commit

Permalink
Merge pull request #14 from Team-UMC/feature/#9/refresh
Browse files Browse the repository at this point in the history
[FEAT] : redis를 이용한 refreshToken 저장
  • Loading branch information
junseokkim authored Jan 13, 2024
2 parents d6df8da + c23942e commit 34c28ba
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 1 deletion.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ dependencies {
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'

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

// swagger setting
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'

Expand Down
8 changes: 7 additions & 1 deletion docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,10 @@ services: # 컨테이너 설정
environment:
- SPRING_PROFILES_ACTIVE=dev
ports:
- 8000:8000
- 8000:8000

redis:
container_name: redis-dev
image: redis
ports:
- 6379:6379
32 changes: 32 additions & 0 deletions src/main/java/com/umc/networkingService/config/RedisConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.umc.networkingService.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;

@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(new StringRedisSerializer());
// Set other serializers if needed
return template;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.umc.networkingService.domain.member.entity;

import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import org.hibernate.annotations.UuidGenerator;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.index.Indexed;

import java.util.UUID;

@AllArgsConstructor
@Getter
@Builder
@RedisHash(value = "jwtToken", timeToLive = 60*60*24*30) // 30일
public class RefreshToken { //redis에 저장할 객체

@Id
@Indexed // 인덱스를 걸어주면 조회할 때 빠르게 찾을 수 있음
private UUID memberId;

private String refreshToken;

/*
만료된 access Token을 가진 memberId 값으로 refresh Token을 찾아와서 유효성을 검사할 예정
*/
}

//memberId 값으로 refresh Token을 찾아와서 유효성을 검사한다.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.umc.networkingService.domain.member.repository;

import com.umc.networkingService.domain.member.entity.RefreshToken;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;
import java.util.UUID;

@Repository
public interface RefreshTokenRepository extends CrudRepository<RefreshToken, String>
{
Optional<RefreshToken> findByMemberId(UUID memberId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.umc.networkingService.domain.member.service;

import com.umc.networkingService.domain.member.entity.RefreshToken;
import com.umc.networkingService.domain.member.repository.RefreshTokenRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;

@Service
@RequiredArgsConstructor
public class RefreshTokenService {

private final RefreshTokenRepository refreshTokenRepository; // Redis에 저장된 refreshToken을 가져오기 위해 DI

@Transactional
public RefreshToken saveTokenInfo(String refreshToken, UUID memberId) { // Redis에 refreshToken 저장
return refreshTokenRepository.save(
RefreshToken.builder()
.memberId(memberId)
.refreshToken(refreshToken)
.build()
);
}

@Transactional
public RefreshToken findByMemberId(UUID memberId) { // 만료된 accessToken으로 refreshToken을 찾아옴
return refreshTokenRepository.findByMemberId(memberId).orElseThrow(() -> new IllegalArgumentException("Refresh Token이 존재하지 않습니다."));
}

@Transactional
public void delete(RefreshToken refreshToken) { // Redis에 저장된 refreshToken 삭제
// Redis에 저장된 refreshToken 삭제
refreshTokenRepository.delete(refreshToken);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.umc.networkingService;

import com.umc.networkingService.domain.member.entity.RefreshToken;
import com.umc.networkingService.domain.member.service.RefreshTokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.junit.jupiter.api.Test;

import java.util.UUID;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
public class RefreshTokenServiceIntegrationTest {

@Autowired
private RefreshTokenService refreshTokenService;


@Test
void testSaveTokenInfo() {

final String REFRESHTOKEN = "testSaveTokenInfo";
final UUID MEMBERID = UUID.randomUUID();


// When
RefreshToken savedToken = refreshTokenService.saveTokenInfo(REFRESHTOKEN, MEMBERID);

// Then (test에서 사용되는 assertion, 조건이 참이 아니라면 테스트 실패)
assertNotNull(savedToken);
assertEquals(REFRESHTOKEN, savedToken.getRefreshToken());
assertEquals(MEMBERID, savedToken.getMemberId());
}

@Test
void testFindByAccessToken() {

final String REFRESHTOKEN = "testFindByAccessToken";
final UUID MEMBERID = UUID.randomUUID();

RefreshToken savedToken = refreshTokenService.saveTokenInfo(REFRESHTOKEN, MEMBERID);

// When
RefreshToken foundToken = refreshTokenService.findByMemberId(MEMBERID);

// Then (test에서 사용되는 assertion, 조건이 참이 아니라면 테스트 실패)
assertNotNull(foundToken);
assertEquals(REFRESHTOKEN, foundToken.getRefreshToken());
assertEquals(MEMBERID, foundToken.getMemberId());

}

@Test
void testDeleteByAccessToken() {

final String REFRESHTOKEN = "testDeleteByAccessToken";
final UUID MEMBERID = UUID.randomUUID();

RefreshToken savedToken = refreshTokenService.saveTokenInfo(REFRESHTOKEN, MEMBERID);

RefreshToken tokenToDelete = refreshTokenService.findByMemberId(MEMBERID);

// When
refreshTokenService.delete(tokenToDelete);

// Then (test에서 사용되는 assertion, 조건이 참이 아니라면 테스트 실패)
assertThrows(IllegalArgumentException.class, () -> refreshTokenService.findByMemberId(MEMBERID));

}
}

0 comments on commit 34c28ba

Please sign in to comment.