diff --git a/Backend/docker-compose.yml b/Backend/docker-compose.yml
index 9ad3a88..ec9cb4e 100644
--- a/Backend/docker-compose.yml
+++ b/Backend/docker-compose.yml
@@ -16,4 +16,9 @@ services:
- ./db:/var/lib/mysql
container_name: chat-db
ports:
- - "3306:3306"
\ No newline at end of file
+ - "3306:3306"
+ memcached:
+ container_name: solsol-memcached
+ image: memcached:alpine
+ ports:
+ - 11211:11211
\ No newline at end of file
diff --git a/Backend/pom.xml b/Backend/pom.xml
index 31e4fbe..f3561a3 100644
--- a/Backend/pom.xml
+++ b/Backend/pom.xml
@@ -115,6 +115,23 @@
2.5
provided
+
+ com.google.code.simple-spring-memcached
+ spring-cache
+ 4.1.3
+
+
+ com.google.code.simple-spring-memcached
+ simple-spring-memcached
+ 4.1.3
+
+
+
+ com.google.code.simple-spring-memcached
+ xmemcached-provider
+ 4.1.3
+
+
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/SolsolApplication.java b/Backend/src/main/java/kimjang/toolkit/solsol/SolsolApplication.java
index 0ac311c..2018084 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/SolsolApplication.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/SolsolApplication.java
@@ -2,7 +2,9 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
+@EnableCaching
@SpringBootApplication
public class SolsolApplication {
public static void main(String[] args) {
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/config/SecurityConfig.java b/Backend/src/main/java/kimjang/toolkit/solsol/config/SecurityConfig.java
index bdf4c42..c5e2a68 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/config/SecurityConfig.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/config/SecurityConfig.java
@@ -2,13 +2,10 @@
import kimjang.toolkit.solsol.config.filter.*;
import kimjang.toolkit.solsol.config.provider.JwtAuthenticationProvider;
-import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
@@ -152,8 +149,4 @@ public PasswordEncoder passwordEncoder(){
// BCrypt 알고리즘을 이용해서 비밀번호를 해싱하자
return new BCryptPasswordEncoder();
}
-
-
-
-
}
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/config/cache/CacheConfig.java b/Backend/src/main/java/kimjang/toolkit/solsol/config/cache/CacheConfig.java
new file mode 100644
index 0000000..dc48c49
--- /dev/null
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/config/cache/CacheConfig.java
@@ -0,0 +1,79 @@
+package kimjang.toolkit.solsol.config.cache;
+
+import com.google.code.ssm.Cache;
+import com.google.code.ssm.CacheFactory;
+import com.google.code.ssm.config.AddressProvider;
+import com.google.code.ssm.config.DefaultAddressProvider;
+import com.google.code.ssm.providers.CacheConfiguration;
+import com.google.code.ssm.providers.xmemcached.MemcacheClientFactoryImpl;
+import com.google.code.ssm.spring.ExtendedSSMCacheManager;
+import com.google.code.ssm.spring.SSMCache;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.ArrayList;
+
+@Slf4j
+@Configuration
+public class CacheConfig extends CachingConfigurerSupport {
+
+ @Value("${spring.cache.address}")
+ private String address;
+
+ @Value("${spring.cache.operationTimeout}")
+ private String operationTimeout;
+
+ @Value("${spring.cache.cacheName}")
+ private String cacheName;
+
+ @Value("${spring.cache.expiration}")
+ private String expiration;
+
+ @Bean
+ public CacheManager cacheManager() {
+
+ CacheFactory cacheFactory = getCacheFactory();
+
+ Cache object = null;
+
+ try {
+ object = cacheFactory.getObject();
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+
+ SSMCache ssmCache = new SSMCache(object, Integer.parseInt(expiration), true);
+
+ ArrayList ssmCaches = new ArrayList<>();
+ ssmCaches.add(0, ssmCache);
+
+ ExtendedSSMCacheManager ssmCacheManager = new ExtendedSSMCacheManager();
+ ssmCacheManager.setCaches(ssmCaches);
+
+ return ssmCacheManager;
+ }
+
+ private CacheFactory getCacheFactory() {
+ CacheConfiguration cacheConfiguration = new CacheConfiguration();
+ cacheConfiguration.setConsistentHashing(true);
+ cacheConfiguration.setUseBinaryProtocol(true);
+ cacheConfiguration.setOperationTimeout(Integer.getInteger(operationTimeout));
+ cacheConfiguration.setUseNameAsKeyPrefix(true);
+ cacheConfiguration.setKeyPrefixSeparator(":");
+
+ MemcacheClientFactoryImpl cacheClientFactory = new MemcacheClientFactoryImpl();
+
+ AddressProvider addressProvider = new DefaultAddressProvider(address);
+
+ CacheFactory cacheFactory = new CacheFactory();
+ cacheFactory.setCacheName(cacheName);
+ cacheFactory.setCacheClientFactory(cacheClientFactory);
+ cacheFactory.setAddressProvider(addressProvider);
+ cacheFactory.setConfiguration(cacheConfiguration);
+ return cacheFactory;
+ }
+}
\ No newline at end of file
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/config/cache/TokenHasher.java b/Backend/src/main/java/kimjang/toolkit/solsol/config/cache/TokenHasher.java
new file mode 100644
index 0000000..18e64ac
--- /dev/null
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/config/cache/TokenHasher.java
@@ -0,0 +1,27 @@
+package kimjang.toolkit.solsol.config.cache;
+
+import org.springframework.stereotype.Component;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+
+@Component
+public class TokenHasher{
+ public String encode(String token){
+ MessageDigest digest = null;
+ try {
+ digest = MessageDigest.getInstance("SHA-256");
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ byte[] encodedhash = digest.digest(token.getBytes(StandardCharsets.UTF_8));
+ return Base64.getEncoder().encodeToString(encodedhash);
+ }
+
+ public boolean matches(String rawToken, String hashedToken) {
+ String hashedRawToken = encode(rawToken);
+ return hashedRawToken.equals(hashedToken);
+ }
+}
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/config/handler/StompHandler.java b/Backend/src/main/java/kimjang/toolkit/solsol/config/handler/StompHandler.java
index 222a28c..17ac705 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/config/handler/StompHandler.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/config/handler/StompHandler.java
@@ -1,7 +1,7 @@
package kimjang.toolkit.solsol.config.handler;
-import kimjang.toolkit.solsol.room.service.ChatRoomSubscribeService;
+import kimjang.toolkit.solsol.domain.room.service.ChatRoomSubscribeService;
import kimjang.toolkit.solsol.config.container.SocketSessionContainer;
import kimjang.toolkit.solsol.config.jwt.SecurityConstants;
import kimjang.toolkit.solsol.config.provider.JwtAuthenticationProvider;
@@ -9,12 +9,9 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
-import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
-import org.springframework.security.authentication.BadCredentialsException;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/config/provider/CustomUserNamePwdAuthenticationProvider.java b/Backend/src/main/java/kimjang/toolkit/solsol/config/provider/CustomUserNamePwdAuthenticationProvider.java
index e3e4313..e6015d1 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/config/provider/CustomUserNamePwdAuthenticationProvider.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/config/provider/CustomUserNamePwdAuthenticationProvider.java
@@ -1,8 +1,8 @@
package kimjang.toolkit.solsol.config.provider;
-import kimjang.toolkit.solsol.user.entities.Authority;
-import kimjang.toolkit.solsol.user.entities.User;
-import kimjang.toolkit.solsol.user.reposiotry.UserRepository;
+import kimjang.toolkit.solsol.domain.user.entities.Authority;
+import kimjang.toolkit.solsol.domain.user.entities.User;
+import kimjang.toolkit.solsol.domain.user.reposiotry.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/domain/cache/RefreshToken.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/cache/RefreshToken.java
new file mode 100644
index 0000000..c6a7a07
--- /dev/null
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/cache/RefreshToken.java
@@ -0,0 +1,28 @@
+package kimjang.toolkit.solsol.domain.cache;
+
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Entity
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class RefreshToken {
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
+ @Column(name = "token_id") // 컬럼의 이름을 바꿀 수 있다.
+ private Long id;
+
+ private String email;
+
+ @Column(name = "refresh_token")
+ private String refreshToken;
+
+ public void setRefreshToken(String refreshToken) {
+ this.refreshToken = refreshToken;
+ }
+}
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/domain/cache/RefreshTokenCacheService.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/cache/RefreshTokenCacheService.java
new file mode 100644
index 0000000..77a0be4
--- /dev/null
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/cache/RefreshTokenCacheService.java
@@ -0,0 +1,55 @@
+package kimjang.toolkit.solsol.domain.cache;
+
+import kimjang.toolkit.solsol.exception.UnauthorizedException;
+import lombok.RequiredArgsConstructor;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+
+@Service
+@RequiredArgsConstructor
+public class RefreshTokenCacheService {
+
+ private final RefreshTokenRepository refreshTokenRepository;
+
+ /**
+ * CachePut은 캐시가 있더라도 메서드를 실행한 결과를 Cache에 저장
+ * 따라서 무조건 새로운 token을 저장하고 싶은 경우 적절
+ * 한 메일에 한 refresh token만 가능!
+ *
+ * @param email
+ * @param hashedRefreshToken : hashing된 refresh token
+ * @return
+ */
+ @CachePut(value= "refresh", key="#email")
+ public String saveToken(String email, String hashedRefreshToken){
+ Optional token = refreshTokenRepository.findByEmail(email);
+ if(token.isPresent()){ // 예전에 로그인해서 refresh token이 남아 있는 경우 업데이트
+ token.get().setRefreshToken(hashedRefreshToken);
+ return refreshTokenRepository.save(token.get()).getRefreshToken();
+ } else{ // 처음 refresh token 만들어서 저장하는 경우
+ RefreshToken newToken = RefreshToken.builder()
+ .email(email)
+ .refreshToken(hashedRefreshToken)
+ .build();
+ return refreshTokenRepository.save(newToken).getRefreshToken();
+ }
+ }
+
+ @CacheEvict(value = "refresh", key = "#email")
+ public void deleteCache(String email){}
+
+ /**
+ * 재발급 용도로 저장된 token 검색
+ * @param email
+ * @return
+ */
+ @Cacheable(value= "refresh")
+ public String searchToken(String email){
+ return refreshTokenRepository.findByEmail(email)
+ .orElseThrow(()-> new UnauthorizedException("인증되지 않았습니다. 다시 시도해주세요.")).getRefreshToken();
+ }
+}
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/domain/cache/RefreshTokenRepository.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/cache/RefreshTokenRepository.java
new file mode 100644
index 0000000..5f3dc36
--- /dev/null
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/cache/RefreshTokenRepository.java
@@ -0,0 +1,11 @@
+package kimjang.toolkit.solsol.domain.cache;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface RefreshTokenRepository extends JpaRepository {
+ Optional findByEmail(String email);
+}
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/message/ChatMessage.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/ChatMessage.java
similarity index 85%
rename from Backend/src/main/java/kimjang/toolkit/solsol/message/ChatMessage.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/message/ChatMessage.java
index cf2e979..b836d1b 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/message/ChatMessage.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/ChatMessage.java
@@ -1,9 +1,9 @@
-package kimjang.toolkit.solsol.message;
+package kimjang.toolkit.solsol.domain.message;
import jakarta.persistence.*;
-import kimjang.toolkit.solsol.user.entities.User;
-import kimjang.toolkit.solsol.message.dto.SendChatMessageDto;
-import kimjang.toolkit.solsol.room.entity.ChatRoom;
+import kimjang.toolkit.solsol.domain.message.dto.SendChatMessageDto;
+import kimjang.toolkit.solsol.domain.room.entity.ChatRoom;
+import kimjang.toolkit.solsol.domain.user.entities.User;
import lombok.*;
import java.time.LocalDateTime;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/message/Greeting.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/Greeting.java
similarity index 80%
rename from Backend/src/main/java/kimjang/toolkit/solsol/message/Greeting.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/message/Greeting.java
index ce71e2a..62dd4d5 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/message/Greeting.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/Greeting.java
@@ -1,4 +1,4 @@
-package kimjang.toolkit.solsol.message;
+package kimjang.toolkit.solsol.domain.message;
public class Greeting {
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/message/GreetingController.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/GreetingController.java
similarity index 77%
rename from Backend/src/main/java/kimjang/toolkit/solsol/message/GreetingController.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/message/GreetingController.java
index 2afccad..00dc0ad 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/message/GreetingController.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/GreetingController.java
@@ -1,12 +1,8 @@
-package kimjang.toolkit.solsol.message;
+package kimjang.toolkit.solsol.domain.message;
-import org.springframework.http.ResponseEntity;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.util.HtmlUtils;
@Controller
public class GreetingController {
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/message/HelloMessage.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/HelloMessage.java
similarity index 84%
rename from Backend/src/main/java/kimjang/toolkit/solsol/message/HelloMessage.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/message/HelloMessage.java
index 605b2c5..b4a3efb 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/message/HelloMessage.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/HelloMessage.java
@@ -1,4 +1,4 @@
-package kimjang.toolkit.solsol.message;
+package kimjang.toolkit.solsol.domain.message;
public class HelloMessage {
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/message/controllor/ChatController.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/controllor/ChatController.java
similarity index 84%
rename from Backend/src/main/java/kimjang/toolkit/solsol/message/controllor/ChatController.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/message/controllor/ChatController.java
index 97a1c0c..1bcc93b 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/message/controllor/ChatController.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/controllor/ChatController.java
@@ -1,19 +1,15 @@
-package kimjang.toolkit.solsol.message.controllor;
+package kimjang.toolkit.solsol.domain.message.controllor;
-import kimjang.toolkit.solsol.message.dto.PastChatsDto;
-import kimjang.toolkit.solsol.message.dto.ReqPastChatsDto;
-import kimjang.toolkit.solsol.message.service.ChatService;
+import kimjang.toolkit.solsol.domain.message.dto.ReqPastChatsDto;
+import kimjang.toolkit.solsol.domain.message.service.ChatService;
+import kimjang.toolkit.solsol.domain.message.dto.PastChatsDto;
import lombok.RequiredArgsConstructor;
-import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
-import java.time.LocalDateTime;
-import java.util.Date;
-
@RestController
@RequiredArgsConstructor
public class ChatController {
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/message/dto/GetChatProj.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/dto/GetChatProj.java
similarity index 74%
rename from Backend/src/main/java/kimjang/toolkit/solsol/message/dto/GetChatProj.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/message/dto/GetChatProj.java
index 1514538..3d8c228 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/message/dto/GetChatProj.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/dto/GetChatProj.java
@@ -1,6 +1,6 @@
-package kimjang.toolkit.solsol.message.dto;
+package kimjang.toolkit.solsol.domain.message.dto;
-import kimjang.toolkit.solsol.user.dto.UserDto;
+import kimjang.toolkit.solsol.domain.user.dto.UserDto;
import java.time.LocalDateTime;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/message/dto/PastChatsDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/dto/PastChatsDto.java
similarity index 94%
rename from Backend/src/main/java/kimjang/toolkit/solsol/message/dto/PastChatsDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/message/dto/PastChatsDto.java
index 87e864b..ab1ded8 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/message/dto/PastChatsDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/dto/PastChatsDto.java
@@ -1,4 +1,4 @@
-package kimjang.toolkit.solsol.message.dto;
+package kimjang.toolkit.solsol.domain.message.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/message/dto/ReqPastChatsDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/dto/ReqPastChatsDto.java
similarity index 94%
rename from Backend/src/main/java/kimjang/toolkit/solsol/message/dto/ReqPastChatsDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/message/dto/ReqPastChatsDto.java
index 507b83e..c56aa28 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/message/dto/ReqPastChatsDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/dto/ReqPastChatsDto.java
@@ -1,4 +1,4 @@
-package kimjang.toolkit.solsol.message.dto;
+package kimjang.toolkit.solsol.domain.message.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/message/dto/SendChatMessageDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/dto/SendChatMessageDto.java
similarity index 94%
rename from Backend/src/main/java/kimjang/toolkit/solsol/message/dto/SendChatMessageDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/message/dto/SendChatMessageDto.java
index edac1ff..97e6620 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/message/dto/SendChatMessageDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/dto/SendChatMessageDto.java
@@ -1,9 +1,9 @@
-package kimjang.toolkit.solsol.message.dto;
+package kimjang.toolkit.solsol.domain.message.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
-import kimjang.toolkit.solsol.user.dto.UserDto;
+import kimjang.toolkit.solsol.domain.user.dto.UserDto;
import lombok.*;
import java.time.LocalDateTime;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/message/repository/ChatRepository.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/repository/ChatRepository.java
similarity index 88%
rename from Backend/src/main/java/kimjang/toolkit/solsol/message/repository/ChatRepository.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/message/repository/ChatRepository.java
index 3c48083..73ed57e 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/message/repository/ChatRepository.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/repository/ChatRepository.java
@@ -1,7 +1,7 @@
-package kimjang.toolkit.solsol.message.repository;
+package kimjang.toolkit.solsol.domain.message.repository;
-import kimjang.toolkit.solsol.message.ChatMessage;
-import kimjang.toolkit.solsol.message.dto.SendChatMessageDto;
+import kimjang.toolkit.solsol.domain.message.ChatMessage;
+import kimjang.toolkit.solsol.domain.message.dto.SendChatMessageDto;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
@@ -10,7 +10,6 @@
import org.springframework.stereotype.Repository;
import java.util.List;
-import java.util.Optional;
@Repository
public interface ChatRepository extends JpaRepository {
@@ -29,7 +28,7 @@ public interface ChatRepository extends JpaRepository {
* @Param roomExitTime : 사용자가 최근 방에서 나간 시간
*/
@Query(value="SELECT " +
- " new kimjang.toolkit.solsol.message.dto.SendChatMessageDto(" +
+ " new kimjang.toolkit.solsol.domain.message.dto.SendChatMessageDto(" +
" :roomId, cm.content, cm.createDate, u.id, u.email, u.name )" + // 채팅 내용
" FROM ChatMessage cm " + // 채팅
" join User u ON u.id = cm.user.id " + // 유저
@@ -46,7 +45,7 @@ public interface ChatRepository extends JpaRepository {
// 유저가 속한 채팅방에 가장 최근 채팅만 쿼리
@Query(value="SELECT " +
- " new kimjang.toolkit.solsol.message.dto.SendChatMessageDto(" +
+ " new kimjang.toolkit.solsol.domain.message.dto.SendChatMessageDto(" +
" :roomId, cm.content, cm.createDate, u.id, u.email, u.name )" + // 채팅 내용
" FROM ChatMessage cm " + // 채팅
" join User u ON u.id = cm.user.id " + // 유저
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/message/service/ChatService.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/service/ChatService.java
similarity index 74%
rename from Backend/src/main/java/kimjang/toolkit/solsol/message/service/ChatService.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/message/service/ChatService.java
index 1c45a1f..a233b3c 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/message/service/ChatService.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/message/service/ChatService.java
@@ -1,14 +1,14 @@
-package kimjang.toolkit.solsol.message.service;
+package kimjang.toolkit.solsol.domain.message.service;
-import kimjang.toolkit.solsol.user.entities.User;
-import kimjang.toolkit.solsol.user.reposiotry.UserRepository;
-import kimjang.toolkit.solsol.message.ChatMessage;
-import kimjang.toolkit.solsol.message.dto.PastChatsDto;
-import kimjang.toolkit.solsol.message.dto.ReqPastChatsDto;
-import kimjang.toolkit.solsol.message.dto.SendChatMessageDto;
-import kimjang.toolkit.solsol.message.repository.ChatRepository;
-import kimjang.toolkit.solsol.room.entity.ChatRoom;
-import kimjang.toolkit.solsol.room.repository.ChatRoomRepository;
+import kimjang.toolkit.solsol.domain.message.dto.ReqPastChatsDto;
+import kimjang.toolkit.solsol.domain.message.repository.ChatRepository;
+import kimjang.toolkit.solsol.domain.room.entity.ChatRoom;
+import kimjang.toolkit.solsol.domain.room.repository.ChatRoomRepository;
+import kimjang.toolkit.solsol.domain.user.entities.User;
+import kimjang.toolkit.solsol.domain.user.reposiotry.UserRepository;
+import kimjang.toolkit.solsol.domain.message.ChatMessage;
+import kimjang.toolkit.solsol.domain.message.dto.PastChatsDto;
+import kimjang.toolkit.solsol.domain.message.dto.SendChatMessageDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Slice;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/ChatRoomController.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/ChatRoomController.java
similarity index 83%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/ChatRoomController.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/ChatRoomController.java
index 840d4f5..1950aa7 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/ChatRoomController.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/ChatRoomController.java
@@ -1,10 +1,13 @@
-package kimjang.toolkit.solsol.room;
+package kimjang.toolkit.solsol.domain.room;
-import kimjang.toolkit.solsol.room.dto.*;
-import kimjang.toolkit.solsol.message.dto.SendChatMessageDto;
-import kimjang.toolkit.solsol.room.service.ChatRoomService;
-import kimjang.toolkit.solsol.room.service.ChatRoomStompService;
-import kimjang.toolkit.solsol.message.service.ChatService;
+import kimjang.toolkit.solsol.domain.room.dto.ChatRoomDto;
+import kimjang.toolkit.solsol.domain.room.dto.CreateChatRoomDto;
+import kimjang.toolkit.solsol.domain.room.dto.InviteChatRoomDto;
+import kimjang.toolkit.solsol.domain.room.dto.LeaveRoomDto;
+import kimjang.toolkit.solsol.domain.message.dto.SendChatMessageDto;
+import kimjang.toolkit.solsol.domain.room.service.ChatRoomService;
+import kimjang.toolkit.solsol.domain.room.service.ChatRoomStompService;
+import kimjang.toolkit.solsol.domain.message.service.ChatService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/dto/ChatRoomDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/ChatRoomDto.java
similarity index 92%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/dto/ChatRoomDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/ChatRoomDto.java
index acbea4f..8bf8522 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/dto/ChatRoomDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/ChatRoomDto.java
@@ -1,4 +1,4 @@
-package kimjang.toolkit.solsol.room.dto;
+package kimjang.toolkit.solsol.domain.room.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/dto/CreateChatRoomDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/CreateChatRoomDto.java
similarity index 78%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/dto/CreateChatRoomDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/CreateChatRoomDto.java
index 7a163a3..093a430 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/dto/CreateChatRoomDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/CreateChatRoomDto.java
@@ -1,6 +1,5 @@
-package kimjang.toolkit.solsol.room.dto;
+package kimjang.toolkit.solsol.domain.room.dto;
-import kimjang.toolkit.solsol.user.dto.UserDto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/dto/CreateRoomReqDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/CreateRoomReqDto.java
similarity index 86%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/dto/CreateRoomReqDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/CreateRoomReqDto.java
index e51b470..00cc039 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/dto/CreateRoomReqDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/CreateRoomReqDto.java
@@ -1,6 +1,6 @@
-package kimjang.toolkit.solsol.room.dto;
+package kimjang.toolkit.solsol.domain.room.dto;
-import kimjang.toolkit.solsol.user.dto.UserDto;
+import kimjang.toolkit.solsol.domain.user.dto.UserDto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/dto/InviteChatRoomDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/InviteChatRoomDto.java
similarity index 86%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/dto/InviteChatRoomDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/InviteChatRoomDto.java
index 96ade9d..ad98f66 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/dto/InviteChatRoomDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/InviteChatRoomDto.java
@@ -1,6 +1,6 @@
-package kimjang.toolkit.solsol.room.dto;
+package kimjang.toolkit.solsol.domain.room.dto;
-import kimjang.toolkit.solsol.user.dto.UserDto;
+import kimjang.toolkit.solsol.domain.user.dto.UserDto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/dto/LastChatDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/LastChatDto.java
similarity index 85%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/dto/LastChatDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/LastChatDto.java
index a7dfb45..6528b51 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/dto/LastChatDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/LastChatDto.java
@@ -1,4 +1,4 @@
-package kimjang.toolkit.solsol.room.dto;
+package kimjang.toolkit.solsol.domain.room.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/dto/LeaveRoomDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/LeaveRoomDto.java
similarity index 68%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/dto/LeaveRoomDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/LeaveRoomDto.java
index 6dcefca..d0a77f7 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/dto/LeaveRoomDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/LeaveRoomDto.java
@@ -1,6 +1,6 @@
-package kimjang.toolkit.solsol.room.dto;
+package kimjang.toolkit.solsol.domain.room.dto;
-import kimjang.toolkit.solsol.user.dto.UserDto;
+import kimjang.toolkit.solsol.domain.user.dto.UserDto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/dto/ReqChatRoomMetaDTO.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/ReqChatRoomMetaDTO.java
similarity index 68%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/dto/ReqChatRoomMetaDTO.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/ReqChatRoomMetaDTO.java
index a8fe308..bab8ecc 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/dto/ReqChatRoomMetaDTO.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/dto/ReqChatRoomMetaDTO.java
@@ -1,6 +1,6 @@
-package kimjang.toolkit.solsol.room.dto;
+package kimjang.toolkit.solsol.domain.room.dto;
-import kimjang.toolkit.solsol.user.dto.UserDto;
+import kimjang.toolkit.solsol.domain.user.dto.UserDto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/entity/ChatRoom.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/entity/ChatRoom.java
similarity index 95%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/entity/ChatRoom.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/entity/ChatRoom.java
index 98eee37..a0027c0 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/entity/ChatRoom.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/entity/ChatRoom.java
@@ -1,4 +1,4 @@
-package kimjang.toolkit.solsol.room.entity;
+package kimjang.toolkit.solsol.domain.room.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.persistence.*;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/entity/ChatRoomCustomerRelationship.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/entity/ChatRoomCustomerRelationship.java
similarity index 87%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/entity/ChatRoomCustomerRelationship.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/entity/ChatRoomCustomerRelationship.java
index 6a2a9e1..3ed5d9a 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/entity/ChatRoomCustomerRelationship.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/entity/ChatRoomCustomerRelationship.java
@@ -1,7 +1,7 @@
-package kimjang.toolkit.solsol.room.entity;
+package kimjang.toolkit.solsol.domain.room.entity;
import jakarta.persistence.*;
-import kimjang.toolkit.solsol.user.entities.User;
+import kimjang.toolkit.solsol.domain.user.entities.User;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/repository/ChatRoomCustormerRelationshipRepository.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/repository/ChatRoomCustormerRelationshipRepository.java
similarity index 78%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/repository/ChatRoomCustormerRelationshipRepository.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/repository/ChatRoomCustormerRelationshipRepository.java
index b4b5cab..07cbb26 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/repository/ChatRoomCustormerRelationshipRepository.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/repository/ChatRoomCustormerRelationshipRepository.java
@@ -1,6 +1,6 @@
-package kimjang.toolkit.solsol.room.repository;
+package kimjang.toolkit.solsol.domain.room.repository;
-import kimjang.toolkit.solsol.room.entity.ChatRoomCustomerRelationship;
+import kimjang.toolkit.solsol.domain.room.entity.ChatRoomCustomerRelationship;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/repository/ChatRoomRepository.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/repository/ChatRoomRepository.java
similarity index 84%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/repository/ChatRoomRepository.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/repository/ChatRoomRepository.java
index a2a2257..2ac7249 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/repository/ChatRoomRepository.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/repository/ChatRoomRepository.java
@@ -1,7 +1,7 @@
-package kimjang.toolkit.solsol.room.repository;
+package kimjang.toolkit.solsol.domain.room.repository;
-import kimjang.toolkit.solsol.room.dto.ChatRoomDto;
-import kimjang.toolkit.solsol.room.entity.ChatRoom;
+import kimjang.toolkit.solsol.domain.room.dto.ChatRoomDto;
+import kimjang.toolkit.solsol.domain.room.entity.ChatRoom;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
@@ -10,7 +10,7 @@
public interface ChatRoomRepository extends JpaRepository {
- @Query("SELECT new kimjang.toolkit.solsol.room.dto.ChatRoomDto( " +
+ @Query("SELECT new kimjang.toolkit.solsol.domain.room.dto.ChatRoomDto( " +
" cr.id, ccr.roomName, cr.memberCnt, ccr.roomExitTime, " +
" (SELECT cm.content FROM ChatMessage cm WHERE cm.chatRoom.id = cr.id AND " + // 채팅 내용 가져오기
" cm.createDate =(SELECT MAX(ccm.createDate) FROM ChatMessage ccm WHERE ccm.chatRoom.id = cm.chatRoom.id)) " + // 채팅방에서 가장 최근 채팅 날짜
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/service/ChatRoomService.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/service/ChatRoomService.java
similarity index 84%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/service/ChatRoomService.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/service/ChatRoomService.java
index 317cd12..b2f454c 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/service/ChatRoomService.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/service/ChatRoomService.java
@@ -1,18 +1,18 @@
-package kimjang.toolkit.solsol.room.service;
-
-import kimjang.toolkit.solsol.room.dto.InviteChatRoomDto;
-import kimjang.toolkit.solsol.room.dto.LeaveRoomDto;
-import kimjang.toolkit.solsol.user.entities.User;
-import kimjang.toolkit.solsol.user.reposiotry.UserRepository;
-import kimjang.toolkit.solsol.user.dto.UserDto;
-import kimjang.toolkit.solsol.message.ChatMessage;
-import kimjang.toolkit.solsol.message.repository.ChatRepository;
-import kimjang.toolkit.solsol.room.dto.ChatRoomDto;
-import kimjang.toolkit.solsol.room.entity.ChatRoom;
-import kimjang.toolkit.solsol.room.entity.ChatRoomCustomerRelationship;
-import kimjang.toolkit.solsol.room.dto.CreateChatRoomDto;
-import kimjang.toolkit.solsol.room.repository.ChatRoomCustormerRelationshipRepository;
-import kimjang.toolkit.solsol.room.repository.ChatRoomRepository;
+package kimjang.toolkit.solsol.domain.room.service;
+
+import kimjang.toolkit.solsol.domain.room.dto.ChatRoomDto;
+import kimjang.toolkit.solsol.domain.room.dto.InviteChatRoomDto;
+import kimjang.toolkit.solsol.domain.room.entity.ChatRoomCustomerRelationship;
+import kimjang.toolkit.solsol.domain.room.repository.ChatRoomRepository;
+import kimjang.toolkit.solsol.domain.user.entities.User;
+import kimjang.toolkit.solsol.domain.room.dto.LeaveRoomDto;
+import kimjang.toolkit.solsol.domain.user.reposiotry.UserRepository;
+import kimjang.toolkit.solsol.domain.user.dto.UserDto;
+import kimjang.toolkit.solsol.domain.message.ChatMessage;
+import kimjang.toolkit.solsol.domain.message.repository.ChatRepository;
+import kimjang.toolkit.solsol.domain.room.entity.ChatRoom;
+import kimjang.toolkit.solsol.domain.room.dto.CreateChatRoomDto;
+import kimjang.toolkit.solsol.domain.room.repository.ChatRoomCustormerRelationshipRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/service/ChatRoomStompService.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/service/ChatRoomStompService.java
similarity index 77%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/service/ChatRoomStompService.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/service/ChatRoomStompService.java
index 88635bb..4f953d0 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/service/ChatRoomStompService.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/service/ChatRoomStompService.java
@@ -1,19 +1,14 @@
-package kimjang.toolkit.solsol.room.service;
+package kimjang.toolkit.solsol.domain.room.service;
-import kimjang.toolkit.solsol.room.dto.CreateChatRoomDto;
-import kimjang.toolkit.solsol.room.dto.CreateRoomReqDto;
-import kimjang.toolkit.solsol.room.dto.InviteChatRoomDto;
+import kimjang.toolkit.solsol.domain.room.dto.InviteChatRoomDto;
+import kimjang.toolkit.solsol.domain.room.dto.CreateRoomReqDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.simp.SimpMessagingTemplate;
-import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.concurrent.CompletableFuture;
-import java.util.stream.Collectors;
-
-import static kimjang.toolkit.solsol.room.service.CreateRoomName.withParticipationsName;
@Slf4j
@Service
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/service/ChatRoomSubscribeService.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/service/ChatRoomSubscribeService.java
similarity index 75%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/service/ChatRoomSubscribeService.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/service/ChatRoomSubscribeService.java
index 92c6fc1..1cde53e 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/service/ChatRoomSubscribeService.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/service/ChatRoomSubscribeService.java
@@ -1,7 +1,7 @@
-package kimjang.toolkit.solsol.room.service;
+package kimjang.toolkit.solsol.domain.room.service;
-import kimjang.toolkit.solsol.room.entity.ChatRoomCustomerRelationship;
-import kimjang.toolkit.solsol.room.repository.ChatRoomCustormerRelationshipRepository;
+import kimjang.toolkit.solsol.domain.room.entity.ChatRoomCustomerRelationship;
+import kimjang.toolkit.solsol.domain.room.repository.ChatRoomCustormerRelationshipRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/room/service/CreateRoomName.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/service/CreateRoomName.java
similarity index 89%
rename from Backend/src/main/java/kimjang/toolkit/solsol/room/service/CreateRoomName.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/room/service/CreateRoomName.java
index 67152a8..0d03a0e 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/room/service/CreateRoomName.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/room/service/CreateRoomName.java
@@ -1,9 +1,6 @@
-package kimjang.toolkit.solsol.room.service;
+package kimjang.toolkit.solsol.domain.room.service;
-import kimjang.toolkit.solsol.user.dto.UserDto;
-import kimjang.toolkit.solsol.room.dto.CreateChatRoomDto;
-
-import java.util.List;
+import kimjang.toolkit.solsol.domain.room.dto.CreateChatRoomDto;
public class CreateRoomName {
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/controller/UserController.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/controller/UserController.java
similarity index 83%
rename from Backend/src/main/java/kimjang/toolkit/solsol/user/controller/UserController.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/user/controller/UserController.java
index 324e08b..44df1bc 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/controller/UserController.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/controller/UserController.java
@@ -1,9 +1,8 @@
-package kimjang.toolkit.solsol.user.controller;
+package kimjang.toolkit.solsol.domain.user.controller;
-import jakarta.servlet.http.HttpServletResponse;
-import kimjang.toolkit.solsol.user.dto.*;
-import kimjang.toolkit.solsol.user.service.FriendService;
-import kimjang.toolkit.solsol.user.service.UserService;
+import kimjang.toolkit.solsol.domain.user.dto.*;
+import kimjang.toolkit.solsol.domain.user.service.FriendService;
+import kimjang.toolkit.solsol.domain.user.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
@@ -11,11 +10,8 @@
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
-import java.net.http.HttpResponse;
import java.util.List;
-import static kimjang.toolkit.solsol.config.jwt.SecurityConstants.JWT_REFRESH_HEADER;
-
@Slf4j
@RestController
@RequiredArgsConstructor
@@ -68,7 +64,7 @@ public ResponseEntity getUserDetail(){
}
@PostMapping("/refresh-token")
- public LoginSuccessDto getAccessTokenByRefreshToken(@RequestBody RefreshDto refreshDto){
+ public IssuedTokens getAccessTokenByRefreshToken(@RequestBody RefreshDto refreshDto){
return userService.getAccessToken(refreshDto);
}
}
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/AddFriendsDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/AddFriendsDto.java
similarity index 82%
rename from Backend/src/main/java/kimjang/toolkit/solsol/user/dto/AddFriendsDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/AddFriendsDto.java
index 585c41f..57ed5bf 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/AddFriendsDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/AddFriendsDto.java
@@ -1,4 +1,4 @@
-package kimjang.toolkit.solsol.user.dto;
+package kimjang.toolkit.solsol.domain.user.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/AuthorityInfo.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/AuthorityInfo.java
new file mode 100644
index 0000000..58596ca
--- /dev/null
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/AuthorityInfo.java
@@ -0,0 +1,15 @@
+package kimjang.toolkit.solsol.domain.user.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class AuthorityInfo {
+ private String email;
+ private String authorities;
+}
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/CreateUserDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/CreateUserDto.java
similarity index 92%
rename from Backend/src/main/java/kimjang/toolkit/solsol/user/dto/CreateUserDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/CreateUserDto.java
index c511fa1..9b3561d 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/CreateUserDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/CreateUserDto.java
@@ -1,4 +1,4 @@
-package kimjang.toolkit.solsol.user.dto;
+package kimjang.toolkit.solsol.domain.user.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/IssuedTokens.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/IssuedTokens.java
new file mode 100644
index 0000000..7d7c669
--- /dev/null
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/IssuedTokens.java
@@ -0,0 +1,15 @@
+package kimjang.toolkit.solsol.domain.user.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class IssuedTokens {
+ private String accessToken;
+ private String refreshToken;
+}
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/LoginDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/LoginDto.java
similarity index 81%
rename from Backend/src/main/java/kimjang/toolkit/solsol/user/dto/LoginDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/LoginDto.java
index d40624c..e17de22 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/LoginDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/LoginDto.java
@@ -1,4 +1,4 @@
-package kimjang.toolkit.solsol.user.dto;
+package kimjang.toolkit.solsol.domain.user.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/LoginSuccessDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/LoginSuccessDto.java
similarity index 92%
rename from Backend/src/main/java/kimjang/toolkit/solsol/user/dto/LoginSuccessDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/LoginSuccessDto.java
index fa58d63..d66ebab 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/LoginSuccessDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/LoginSuccessDto.java
@@ -1,4 +1,4 @@
-package kimjang.toolkit.solsol.user.dto;
+package kimjang.toolkit.solsol.domain.user.dto;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/RefreshDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/RefreshDto.java
new file mode 100644
index 0000000..0c819dc
--- /dev/null
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/RefreshDto.java
@@ -0,0 +1,12 @@
+package kimjang.toolkit.solsol.domain.user.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public class RefreshDto {
+ private String refreshToken;
+}
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/UserDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/UserDto.java
similarity index 88%
rename from Backend/src/main/java/kimjang/toolkit/solsol/user/dto/UserDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/UserDto.java
index 4aa28fe..a1ce41d 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/UserDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/UserDto.java
@@ -1,8 +1,8 @@
-package kimjang.toolkit.solsol.user.dto;
+package kimjang.toolkit.solsol.domain.user.dto;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
-import kimjang.toolkit.solsol.user.entities.User;
+import kimjang.toolkit.solsol.domain.user.entities.User;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/UserProfileDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/UserProfileDto.java
similarity index 91%
rename from Backend/src/main/java/kimjang/toolkit/solsol/user/dto/UserProfileDto.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/UserProfileDto.java
index c6af763..8b49c93 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/UserProfileDto.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/dto/UserProfileDto.java
@@ -1,4 +1,4 @@
-package kimjang.toolkit.solsol.user.dto;
+package kimjang.toolkit.solsol.domain.user.dto;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/entities/Authority.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/entities/Authority.java
similarity index 92%
rename from Backend/src/main/java/kimjang/toolkit/solsol/user/entities/Authority.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/user/entities/Authority.java
index f111299..b0e861d 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/entities/Authority.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/entities/Authority.java
@@ -1,4 +1,4 @@
-package kimjang.toolkit.solsol.user.entities;
+package kimjang.toolkit.solsol.domain.user.entities;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/entities/Friend.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/entities/Friend.java
similarity index 94%
rename from Backend/src/main/java/kimjang/toolkit/solsol/user/entities/Friend.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/user/entities/Friend.java
index 8b734c1..49884b3 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/entities/Friend.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/entities/Friend.java
@@ -1,4 +1,4 @@
-package kimjang.toolkit.solsol.user.entities;
+package kimjang.toolkit.solsol.domain.user.entities;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/entities/User.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/entities/User.java
similarity index 94%
rename from Backend/src/main/java/kimjang/toolkit/solsol/user/entities/User.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/user/entities/User.java
index 32f28ad..f992882 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/entities/User.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/entities/User.java
@@ -1,7 +1,7 @@
-package kimjang.toolkit.solsol.user.entities;
+package kimjang.toolkit.solsol.domain.user.entities;
import jakarta.persistence.*;
-import kimjang.toolkit.solsol.user.dto.CreateUserDto;
+import kimjang.toolkit.solsol.domain.user.dto.CreateUserDto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/reposiotry/FriendRepository.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/reposiotry/FriendRepository.java
similarity index 70%
rename from Backend/src/main/java/kimjang/toolkit/solsol/user/reposiotry/FriendRepository.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/user/reposiotry/FriendRepository.java
index c42659a..246421c 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/reposiotry/FriendRepository.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/reposiotry/FriendRepository.java
@@ -1,7 +1,7 @@
-package kimjang.toolkit.solsol.user.reposiotry;
+package kimjang.toolkit.solsol.domain.user.reposiotry;
-import kimjang.toolkit.solsol.user.entities.Friend;
-import kimjang.toolkit.solsol.user.dto.UserProfileDto;
+import kimjang.toolkit.solsol.domain.user.dto.UserProfileDto;
+import kimjang.toolkit.solsol.domain.user.entities.Friend;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
@@ -10,7 +10,7 @@
public interface FriendRepository extends JpaRepository {
- @Query(value = "SELECT distinct new kimjang.toolkit.solsol.user.dto.UserProfileDto( " +
+ @Query(value = "SELECT distinct new kimjang.toolkit.solsol.domain.user.dto.UserProfileDto( " +
" f.subUser.id, f.subUser.email, f.subUser.name, f.subUser.imgUrl ) FROM Friend f " +
" JOIN User u ON f.user = u" +
" WHERE u.email = :email") // 이메일이 email인 유저가 main인 f만 존재~
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/reposiotry/UserRepository.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/reposiotry/UserRepository.java
similarity index 72%
rename from Backend/src/main/java/kimjang/toolkit/solsol/user/reposiotry/UserRepository.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/user/reposiotry/UserRepository.java
index 9c8cef6..612d03f 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/reposiotry/UserRepository.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/reposiotry/UserRepository.java
@@ -1,7 +1,7 @@
-package kimjang.toolkit.solsol.user.reposiotry;
+package kimjang.toolkit.solsol.domain.user.reposiotry;
-import kimjang.toolkit.solsol.user.entities.User;
-import kimjang.toolkit.solsol.user.dto.UserProfileDto;
+import kimjang.toolkit.solsol.domain.user.dto.UserProfileDto;
+import kimjang.toolkit.solsol.domain.user.entities.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
@@ -15,7 +15,7 @@ public interface UserRepository extends JpaRepository {
@Query(value = "select u from User u join FETCH u.authorities a WHERE u.email = :email")
Optional findByEmail(@Param("email") String email);
- @Query(value = "select new kimjang.toolkit.solsol.user.dto.UserProfileDto(" +
+ @Query(value = "select new kimjang.toolkit.solsol.domain.user.dto.UserProfileDto(" +
" u.id, u.email, u.name, u.imgUrl ) from User u WHERE u.email = :email")
UserProfileDto findProfileByEmail(@Param("email") String email);
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/service/FriendService.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/service/FriendService.java
similarity index 78%
rename from Backend/src/main/java/kimjang/toolkit/solsol/user/service/FriendService.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/user/service/FriendService.java
index 94ddd95..a82d402 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/service/FriendService.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/service/FriendService.java
@@ -1,11 +1,11 @@
-package kimjang.toolkit.solsol.user.service;
+package kimjang.toolkit.solsol.domain.user.service;
-import kimjang.toolkit.solsol.user.entities.Friend;
-import kimjang.toolkit.solsol.user.entities.User;
-import kimjang.toolkit.solsol.user.reposiotry.FriendRepository;
-import kimjang.toolkit.solsol.user.reposiotry.UserRepository;
-import kimjang.toolkit.solsol.user.dto.AddFriendsDto;
-import kimjang.toolkit.solsol.user.dto.UserProfileDto;
+import kimjang.toolkit.solsol.domain.user.dto.AddFriendsDto;
+import kimjang.toolkit.solsol.domain.user.dto.UserProfileDto;
+import kimjang.toolkit.solsol.domain.user.entities.Friend;
+import kimjang.toolkit.solsol.domain.user.entities.User;
+import kimjang.toolkit.solsol.domain.user.reposiotry.FriendRepository;
+import kimjang.toolkit.solsol.domain.user.reposiotry.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/service/JwtIssuer.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/service/JwtIssuer.java
new file mode 100644
index 0000000..8d252ff
--- /dev/null
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/service/JwtIssuer.java
@@ -0,0 +1,143 @@
+package kimjang.toolkit.solsol.domain.user.service;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.ExpiredJwtException;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.MalformedJwtException;
+import io.jsonwebtoken.security.Keys;
+import io.jsonwebtoken.security.SignatureException;
+import kimjang.toolkit.solsol.config.cache.TokenHasher;
+import kimjang.toolkit.solsol.config.jwt.JwtInvalidException;
+import kimjang.toolkit.solsol.config.jwt.SecurityConstants;
+import kimjang.toolkit.solsol.domain.cache.RefreshToken;
+import kimjang.toolkit.solsol.domain.cache.RefreshTokenCacheService;
+import kimjang.toolkit.solsol.domain.user.dto.AuthorityInfo;
+import kimjang.toolkit.solsol.domain.user.dto.IssuedTokens;
+import kimjang.toolkit.solsol.domain.user.dto.RefreshDto;
+import kimjang.toolkit.solsol.domain.user.entities.Authority;
+import kimjang.toolkit.solsol.exception.UnauthorizedException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.SecretKey;
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
+import java.util.Set;
+
+@Slf4j
+@Component
+public class JwtIssuer {
+ private final SecretKey key = Keys.hmacShaKeyFor(SecurityConstants.JWT_KEY.getBytes(StandardCharsets.UTF_8));
+ private final Long ONE_SECONDS = 1000L;
+ private final Long ONE_MINUTE = 60 * ONE_SECONDS;
+ private final long accessExpireMin;
+ private final long refreshExpireMin;
+ private final RefreshTokenCacheService refreshTokenCacheService;
+ private final TokenHasher tokenHasher;
+
+ public JwtIssuer(@Value("${jwt.access-expire-min:10}") long accessExpireMin,
+ @Value("${jwt.refresh-expire-min:60}") long refreshExpireMin,
+ RefreshTokenCacheService refreshTokenCacheService,
+ TokenHasher tokenHasher){
+ this.accessExpireMin = accessExpireMin;
+ this.refreshExpireMin = refreshExpireMin;
+ this.refreshTokenCacheService = refreshTokenCacheService;
+ this.tokenHasher = tokenHasher;
+ }
+
+ /**
+ * refresh token 재발급 시 호출되는 메서드!
+ * 요청된 refresh token을 바탕으로 email을 찾고
+ * 새로운 tokens를 발급하고 캐시와 DB에 저장!
+ * @param refreshDto
+ * @return
+ */
+ public IssuedTokens getAccessTokenByRefreshToken(RefreshDto refreshDto) {
+ try {
+ AuthorityInfo authorityInfo = getAuthorityInfo(refreshDto);
+ // cache hit 저장된 토큰 그대로 가져옴
+ String savedRefreshToken = refreshTokenCacheService.searchToken(authorityInfo.getEmail());
+ // 저장된 refresh token과 같은지 확인 같을 때 재발급 가능!
+ hashMatchingTokens(refreshDto.getRefreshToken(), savedRefreshToken);
+
+ // 기존 토큰 제거하기
+ refreshTokenCacheService.deleteCache(authorityInfo.getEmail());
+ // 새로운 토큰 재발급
+ IssuedTokens issuedTokens = getAccessTokenByAuthorityInfo(authorityInfo);
+ // 새로운 토큰 저장하기
+ saveIssuedToken(authorityInfo.getEmail(), issuedTokens.getRefreshToken());
+ return issuedTokens;
+
+ } catch (SignatureException signatureException) {
+ throw new JwtInvalidException("signature key is different", signatureException);
+ } catch (ExpiredJwtException expiredJwtException) {
+ throw new JwtInvalidException("expired token", expiredJwtException);
+ } catch (MalformedJwtException malformedJwtException) {
+ throw new JwtInvalidException("malformed token", malformedJwtException);
+ } catch (IllegalArgumentException illegalArgumentException) {
+ throw new JwtInvalidException("using illegal argument like null", illegalArgumentException);
+ }
+ }
+
+ private void hashMatchingTokens(String refreshToken, String savedRefreshToken){
+ // hash match check
+ if(!tokenHasher.matches(refreshToken, savedRefreshToken)){
+ throw new UnauthorizedException("refresh token is already used");
+ }
+ log.info("존재하는 token과 같은 token을 가지고 있습니다.");
+ }
+
+ private AuthorityInfo getAuthorityInfo(RefreshDto refreshDto) {
+ Claims claims = Jwts.parser()
+ .verifyWith(key) // 서버가 저장하고 있는 키로 payload 암호 풀기
+ .build()
+ .parseSignedClaims(refreshDto.getRefreshToken())
+ .getPayload();
+ String email = (String) claims.get("email");
+ String authorities = (String) claims.get("authorities");
+
+ return AuthorityInfo.builder()
+ .email(email)
+ .authorities(authorities).build();
+ }
+
+ public IssuedTokens getAccessTokenByAuthorityInfo(AuthorityInfo authorityInfo) {
+ String accessToken = getAccessToken(authorityInfo);
+ String refreshToken = getRefreshToken(authorityInfo);
+ return IssuedTokens.builder()
+ .accessToken(accessToken)
+ .refreshToken(refreshToken)
+ .build();
+ }
+
+ public String getAccessToken(AuthorityInfo authorityInfo) {
+ log.info("유통기한 : {}",accessExpireMin*ONE_MINUTE);
+ return getToken(authorityInfo.getEmail(), authorityInfo.getAuthorities(), accessExpireMin*ONE_MINUTE);
+ }
+ public String getRefreshToken(AuthorityInfo authorityInfo) {
+ return getToken(authorityInfo.getEmail(), authorityInfo.getAuthorities(), refreshExpireMin*ONE_MINUTE);
+ }
+
+ private String getToken(String email, String authorities, Long expireTime) {
+ long now = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
+ return Jwts.builder().issuer("Sol-Kimjang").subject("JWT Token")
+ // 비밀번호는 절대 안된다.
+ .claim("email", email)
+ .claim("authorities", authorities)
+ .claim("create_date", LocalDateTime.now().toString()) // 생성 시간을 둬서 여러번 생성되는 것을 방지하기
+ .issuedAt(new Date(now))
+ // 만료시간, ms 단위, 만료 시간을 넘어선 토큰이 들어오면 만료됐다고 예외가 발생한다.
+ .expiration(new Date(now + expireTime))
+ // 디지털 서명 작성
+ .signWith(key).compact();
+ }
+
+ public void saveIssuedToken(String email, String refreshToken) {
+ String hashedRefreshToken = tokenHasher.encode(refreshToken);
+ refreshTokenCacheService.saveToken(email, hashedRefreshToken);
+ }
+}
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/service/UserService.java b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/service/UserService.java
similarity index 61%
rename from Backend/src/main/java/kimjang/toolkit/solsol/user/service/UserService.java
rename to Backend/src/main/java/kimjang/toolkit/solsol/domain/user/service/UserService.java
index 955a895..666be81 100644
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/service/UserService.java
+++ b/Backend/src/main/java/kimjang/toolkit/solsol/domain/user/service/UserService.java
@@ -1,9 +1,10 @@
-package kimjang.toolkit.solsol.user.service;
+package kimjang.toolkit.solsol.domain.user.service;
+import kimjang.toolkit.solsol.domain.user.dto.*;
+import kimjang.toolkit.solsol.domain.user.entities.Authority;
import kimjang.toolkit.solsol.exception.UnauthorizedException;
-import kimjang.toolkit.solsol.user.entities.User;
-import kimjang.toolkit.solsol.user.dto.*;
-import kimjang.toolkit.solsol.user.reposiotry.UserRepository;
+import kimjang.toolkit.solsol.domain.user.entities.User;
+import kimjang.toolkit.solsol.domain.user.reposiotry.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException;
@@ -14,7 +15,9 @@
import org.springframework.transaction.annotation.Transactional;
import javax.naming.AuthenticationException;
+import java.util.HashSet;
import java.util.Optional;
+import java.util.Set;
@Slf4j
@Service
@@ -23,6 +26,7 @@ public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final JwtIssuer jwtIssuer;
+
@Transactional
public UserDto registerUser(CreateUserDto createUserDto){
String hashPwd = passwordEncoder.encode(createUserDto.getPwd());
@@ -44,6 +48,12 @@ public UserDto findByEmail(String email){
return UserDto.toDto(user);
}
+ /**
+ * 유저가 처음으로 로그인할 때 생성되는 로그인 결과 값 LoginSuccessDto
+ *
+ * @param loginDto
+ * @return
+ */
public LoginSuccessDto userLoginAndSaveRefreshToken(LoginDto loginDto){
try{
User user = userRepository.findByEmail(loginDto.getEmail())
@@ -53,22 +63,39 @@ public LoginSuccessDto userLoginAndSaveRefreshToken(LoginDto loginDto){
throw new BadCredentialsException("bad credential: using unmatched password");
}
log.info("email : "+loginDto.getEmail());
- String accessToken = jwtIssuer.getAccessToken(user.getEmail(), user.getAuthorities());
- String refreshToken = jwtIssuer.getRefreshToken(user.getEmail(), user.getAuthorities());
+ String authorities = populateAuthorities(user.getAuthorities());
+ AuthorityInfo authorityInfo = AuthorityInfo.builder().email(user.getEmail())
+ .authorities(authorities).build();
+ // 새로운 tokens 재발급
+ IssuedTokens tokens = jwtIssuer.getAccessTokenByAuthorityInfo(authorityInfo);
+ // 재발급한 tokens Cache와 DB에 저장
+ jwtIssuer.saveIssuedToken(user.getEmail(), tokens.getRefreshToken());
return LoginSuccessDto.builder()
.id(user.getId())
.email(user.getEmail())
.name(user.getName())
.imgUrl(user.getImgUrl())
- .accessToken(accessToken)
- .refreshToken(refreshToken)
+ .accessToken(tokens.getAccessToken())
+ .refreshToken(tokens.getRefreshToken())
.build();
} catch (AuthenticationException e){
throw new RuntimeException(e.getMessage(), e);
}
}
- public LoginSuccessDto getAccessToken(RefreshDto refreshDto) {
+ /**
+ * 기존 refresh token으로 새로운 로그인 결과 값 LoginSuccessDto을 생성
+ * @param refreshDto
+ * @return
+ */
+ public IssuedTokens getAccessToken(RefreshDto refreshDto) {
+ /**
+ * 캐시나 DB에 존재하는 refresh token인지 확인
+ * - 없으면 401 에러
+ * - 있으면 기존꺼 지우고 새로운 값으로 업데이트 (Cacheput)
+ * - refresh token의 만료시간까지 사용되지 않으면 제거
+ */
+
return jwtIssuer.getAccessTokenByRefreshToken(refreshDto);
}
@@ -81,4 +108,12 @@ public UserProfileDto getUserDetail() {
}
return userRepository.findProfileByEmail(userEmail);
}
+
+ private String populateAuthorities(Set collection) {
+ Set authoritiesSet = new HashSet<>();
+ for (Authority authority : collection) {
+ authoritiesSet.add(authority.getName());
+ }
+ return String.join(",", authoritiesSet);
+ }
}
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/RefreshDto.java b/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/RefreshDto.java
deleted file mode 100644
index f996bae..0000000
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/dto/RefreshDto.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package kimjang.toolkit.solsol.user.dto;
-
-import lombok.Getter;
-
-@Getter
-public class RefreshDto {
- private String refreshToken;
-}
diff --git a/Backend/src/main/java/kimjang/toolkit/solsol/user/service/JwtIssuer.java b/Backend/src/main/java/kimjang/toolkit/solsol/user/service/JwtIssuer.java
deleted file mode 100644
index dc299a4..0000000
--- a/Backend/src/main/java/kimjang/toolkit/solsol/user/service/JwtIssuer.java
+++ /dev/null
@@ -1,104 +0,0 @@
-package kimjang.toolkit.solsol.user.service;
-
-import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.ExpiredJwtException;
-import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.MalformedJwtException;
-import io.jsonwebtoken.security.Keys;
-import io.jsonwebtoken.security.SignatureException;
-import kimjang.toolkit.solsol.config.jwt.JwtInvalidException;
-import kimjang.toolkit.solsol.config.jwt.SecurityConstants;
-import kimjang.toolkit.solsol.user.entities.Authority;
-import kimjang.toolkit.solsol.user.dto.LoginSuccessDto;
-import kimjang.toolkit.solsol.user.dto.RefreshDto;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-
-import javax.crypto.SecretKey;
-import java.nio.charset.StandardCharsets;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
-
-@Slf4j
-@Component
-public class JwtIssuer {
- private final SecretKey key = Keys.hmacShaKeyFor(SecurityConstants.JWT_KEY.getBytes(StandardCharsets.UTF_8));
- private final Long ONE_SECONDS = 1000L;
- private final Long ONE_MINUTE = 60 * ONE_SECONDS;
- private final long accessExpireMin;
- private final long refreshExpireMin;
- public JwtIssuer(@Value("${jwt.access-expire-min:10}") long accessExpireMin,
- @Value("${jwt.refresh-expire-min:60}") long refreshExpireMin){
- this.accessExpireMin = accessExpireMin;
- this.refreshExpireMin = refreshExpireMin;
- }
-
- private String getToken(String email, String authorities, Long expireTime) {
- log.info("authories : {}",authorities);
- long now = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
- return Jwts.builder().issuer("Sol-Kimjang").subject("JWT Token")
- // 비밀번호는 절대 안된다.
- .claim("email", email)
- .claim("authorities", authorities)
- .issuedAt(new Date(now))
- // 만료시간, ms 단위, 만료 시간을 넘어선 토큰이 들어오면 만료됐다고 예외가 발생한다.
- .expiration(new Date(now + expireTime))
- // 디지털 서명 작성
- .signWith(key).compact();
- }
-
- private String populateAuthorities(Set collection) {
- Set authoritiesSet = new HashSet<>();
- for (Authority authority : collection) {
- authoritiesSet.add(authority.getName());
- }
- return String.join(",", authoritiesSet);
- }
-
- public String getAccessToken(String email, Set authorities) {
- log.info("유통기한 : {}",accessExpireMin*ONE_MINUTE);
- return getToken(email, populateAuthorities(authorities), accessExpireMin*ONE_MINUTE);
- }
- public String getRefreshToken(String email, Set authorities) {
- return getToken(email, populateAuthorities(authorities), refreshExpireMin*ONE_MINUTE);
- }
- public String getAccessToken(String email, String authorities) {
- log.info("유통기한 : {}",accessExpireMin*ONE_MINUTE);
- return getToken(email, authorities, accessExpireMin*ONE_MINUTE);
- }
- public String getRefreshToken(String email, String authorities) {
- return getToken(email, authorities, refreshExpireMin*ONE_MINUTE);
- }
-
- public LoginSuccessDto getAccessTokenByRefreshToken(RefreshDto refreshDto) {
- try {
- Claims claims = Jwts.parser()
- .verifyWith(key) // 서버가 저장하고 있는 키로 payload 암호 풀기
- .build()
- .parseSignedClaims(refreshDto.getRefreshToken())
- .getPayload();
- String email = (String) claims.get("email");
- String authorities = (String) claims.get("authorities");
-
- String accessToken = getAccessToken(email, authorities);
- String refreshToken = getRefreshToken(email, authorities);
- return LoginSuccessDto.builder()
- .accessToken(accessToken)
- .refreshToken(refreshToken)
- .build();
- } catch (SignatureException signatureException) {
- throw new JwtInvalidException("signature key is different", signatureException);
- } catch (ExpiredJwtException expiredJwtException) {
- throw new JwtInvalidException("expired token", expiredJwtException);
- } catch (MalformedJwtException malformedJwtException) {
- throw new JwtInvalidException("malformed token", malformedJwtException);
- } catch (IllegalArgumentException illegalArgumentException) {
- throw new JwtInvalidException("using illegal argument like null", illegalArgumentException);
- }
-
- }
-}
diff --git a/Backend/src/main/resources/application-dev.properties b/Backend/src/main/resources/application-dev.properties
index 3dead11..8e925ae 100644
--- a/Backend/src/main/resources/application-dev.properties
+++ b/Backend/src/main/resources/application-dev.properties
@@ -15,8 +15,14 @@ spring.datasource.username=root
spring.datasource.password=sol-root
spring.jpa.hibernate.ddl-auto= update
spring.datasource.url=jdbc:mysql://localhost:3306/chat
-spring.jpa.show-sql=true
-spring.jpa.properties.hibernate.format_sql= true
+spring.jpa.show-sql=false
+spring.jpa.properties.hibernate.format_sql= false
# swagger
-#springdoc.swagger-ui.path=/swagger-ui.html
\ No newline at end of file
+#springdoc.swagger-ui.path=/swagger-ui.html
+
+# memcached
+spring.cache.operationTimeout: 1500
+spring.cache.cacheName: refresh
+spring.cache.expiration: 600
+spring.cache.address: localhost:11211
diff --git a/Backend/src/main/resources/application-prod.properties b/Backend/src/main/resources/application-prod.properties
index 97a2fbd..a6235d3 100644
--- a/Backend/src/main/resources/application-prod.properties
+++ b/Backend/src/main/resources/application-prod.properties
@@ -21,3 +21,9 @@ spring.jpa.show-sql=true
## aws RDS certification
spring.datasource.username=chat_rds
spring.datasource.password=chat-rds-root
+
+# memcached
+spring.cache.operationTimeout: 1500
+spring.cache.cacheName: refresh
+spring.cache.expiration: 600
+spring.cache.address: kimjang-token-cache-cgl9vt.serverless.apn2.cache.amazonaws.com:11212
diff --git a/Backend/src/test/java/kimjang/toolkit/solsol/chat/CreateChatTest.java b/Backend/src/test/java/kimjang/toolkit/solsol/chat/CreateChatTest.java
index 0cd6305..903f15b 100644
--- a/Backend/src/test/java/kimjang/toolkit/solsol/chat/CreateChatTest.java
+++ b/Backend/src/test/java/kimjang/toolkit/solsol/chat/CreateChatTest.java
@@ -2,10 +2,10 @@
import kimjang.toolkit.solsol.SolsolApplication;
-import kimjang.toolkit.solsol.user.dto.UserDto;
-import kimjang.toolkit.solsol.message.ChatMessage;
-import kimjang.toolkit.solsol.message.dto.SendChatMessageDto;
-import kimjang.toolkit.solsol.message.service.ChatService;
+import kimjang.toolkit.solsol.domain.user.dto.UserDto;
+import kimjang.toolkit.solsol.domain.message.ChatMessage;
+import kimjang.toolkit.solsol.domain.message.dto.SendChatMessageDto;
+import kimjang.toolkit.solsol.domain.message.service.ChatService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
diff --git a/Backend/src/test/java/kimjang/toolkit/solsol/chat/GetPastChatsTest.java b/Backend/src/test/java/kimjang/toolkit/solsol/chat/GetPastChatsTest.java
index c233b7f..a97fae2 100644
--- a/Backend/src/test/java/kimjang/toolkit/solsol/chat/GetPastChatsTest.java
+++ b/Backend/src/test/java/kimjang/toolkit/solsol/chat/GetPastChatsTest.java
@@ -1,17 +1,15 @@
package kimjang.toolkit.solsol.chat;
-import kimjang.toolkit.solsol.message.dto.PastChatsDto;
-import kimjang.toolkit.solsol.message.dto.ReqPastChatsDto;
-import kimjang.toolkit.solsol.message.service.ChatService;
+import kimjang.toolkit.solsol.domain.message.dto.PastChatsDto;
+import kimjang.toolkit.solsol.domain.message.dto.ReqPastChatsDto;
+import kimjang.toolkit.solsol.domain.message.service.ChatService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
-import java.time.LocalDateTime;
-
@SpringBootTest
public class GetPastChatsTest {
@Autowired
diff --git a/Backend/src/test/java/kimjang/toolkit/solsol/chat/LoadPastChatsTest.java b/Backend/src/test/java/kimjang/toolkit/solsol/chat/LoadPastChatsTest.java
index e622927..659d68d 100644
--- a/Backend/src/test/java/kimjang/toolkit/solsol/chat/LoadPastChatsTest.java
+++ b/Backend/src/test/java/kimjang/toolkit/solsol/chat/LoadPastChatsTest.java
@@ -1,8 +1,8 @@
package kimjang.toolkit.solsol.chat;
-import kimjang.toolkit.solsol.message.dto.PastChatsDto;
-import kimjang.toolkit.solsol.message.dto.ReqPastChatsDto;
-import kimjang.toolkit.solsol.message.service.ChatService;
+import kimjang.toolkit.solsol.domain.message.dto.PastChatsDto;
+import kimjang.toolkit.solsol.domain.message.dto.ReqPastChatsDto;
+import kimjang.toolkit.solsol.domain.message.service.ChatService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
diff --git a/Backend/src/test/java/kimjang/toolkit/solsol/integrationTest/InviteIntegrationTests.java b/Backend/src/test/java/kimjang/toolkit/solsol/integrationTest/InviteIntegrationTests.java
index 0799a52..adfcd61 100644
--- a/Backend/src/test/java/kimjang/toolkit/solsol/integrationTest/InviteIntegrationTests.java
+++ b/Backend/src/test/java/kimjang/toolkit/solsol/integrationTest/InviteIntegrationTests.java
@@ -3,14 +3,10 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
-import kimjang.toolkit.solsol.message.ChatMessage;
-import kimjang.toolkit.solsol.message.dto.SendChatMessageDto;
-import kimjang.toolkit.solsol.room.ChatRoomController;
-import kimjang.toolkit.solsol.room.dto.CreateChatRoomDto;
-import kimjang.toolkit.solsol.room.dto.CreateRoomReqDto;
-import kimjang.toolkit.solsol.room.dto.InviteChatRoomDto;
-import kimjang.toolkit.solsol.room.service.ChatRoomService;
-import kimjang.toolkit.solsol.user.dto.UserDto;
+import kimjang.toolkit.solsol.domain.room.ChatRoomController;
+import kimjang.toolkit.solsol.domain.room.dto.CreateChatRoomDto;
+import kimjang.toolkit.solsol.domain.room.dto.CreateRoomReqDto;
+import kimjang.toolkit.solsol.domain.room.dto.InviteChatRoomDto;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
diff --git a/Backend/src/test/java/kimjang/toolkit/solsol/integrationTest/MessageIntegrationTests.java b/Backend/src/test/java/kimjang/toolkit/solsol/integrationTest/MessageIntegrationTests.java
index 4343657..6131993 100644
--- a/Backend/src/test/java/kimjang/toolkit/solsol/integrationTest/MessageIntegrationTests.java
+++ b/Backend/src/test/java/kimjang/toolkit/solsol/integrationTest/MessageIntegrationTests.java
@@ -3,8 +3,8 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
-import kimjang.toolkit.solsol.user.dto.UserDto;
-import kimjang.toolkit.solsol.message.dto.SendChatMessageDto;
+import kimjang.toolkit.solsol.domain.user.dto.UserDto;
+import kimjang.toolkit.solsol.domain.message.dto.SendChatMessageDto;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
diff --git a/Backend/src/test/java/kimjang/toolkit/solsol/jwt/ReIssueTokenTest.java b/Backend/src/test/java/kimjang/toolkit/solsol/jwt/ReIssueTokenTest.java
new file mode 100644
index 0000000..589fbff
--- /dev/null
+++ b/Backend/src/test/java/kimjang/toolkit/solsol/jwt/ReIssueTokenTest.java
@@ -0,0 +1,137 @@
+package kimjang.toolkit.solsol.jwt;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.security.Keys;
+import kimjang.toolkit.solsol.config.cache.TokenHasher;
+import kimjang.toolkit.solsol.config.jwt.SecurityConstants;
+import kimjang.toolkit.solsol.domain.cache.RefreshTokenCacheService;
+import kimjang.toolkit.solsol.domain.user.dto.AuthorityInfo;
+import kimjang.toolkit.solsol.domain.user.dto.IssuedTokens;
+import kimjang.toolkit.solsol.domain.user.dto.RefreshDto;
+import kimjang.toolkit.solsol.domain.user.service.JwtIssuer;
+import kimjang.toolkit.solsol.exception.UnauthorizedException;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.crypto.SecretKey;
+import java.nio.charset.StandardCharsets;
+
+@Slf4j
+@SpringBootTest
+@Transactional
+public class ReIssueTokenTest {
+ private final SecretKey key = Keys.hmacShaKeyFor(SecurityConstants.JWT_KEY.getBytes(StandardCharsets.UTF_8));
+ @Autowired
+ private TokenHasher tokenHasher;
+
+ @Autowired
+ private RefreshTokenCacheService refreshTokenCacheService;
+
+ @Autowired
+ private JwtIssuer jwtIssuer;
+
+ @Autowired
+ private PasswordEncoder bCryptPasswordEncoder;
+
+ private IssuedTokens issuedTokens;
+ private final String email = "solsol@gmail.com";
+ private final AuthorityInfo authorityInfo1 = AuthorityInfo.builder()
+ .email(email).authorities("ROLE_USER").build();
+ private final AuthorityInfo authorityInfo2 = AuthorityInfo.builder()
+ .email("email").authorities("ROLE_USER").build();
+
+ @Test
+ public void when_reissue_then_not_equal_made_time(){
+ // 토큰 생성
+ issuedTokens = jwtIssuer.getAccessTokenByAuthorityInfo(authorityInfo1);
+ // 토큰 저장
+ jwtIssuer.saveIssuedToken(email, issuedTokens.getRefreshToken());
+ String time1 = getCreatedTime(issuedTokens.getRefreshToken());
+ log.info("초기 refresh token 생성 시간 : {}",time1);
+ // 처음 생성
+ IssuedTokens newIssuedTokens = jwtIssuer.getAccessTokenByRefreshToken(new RefreshDto(issuedTokens.getRefreshToken()));
+ String time2 = getCreatedTime(newIssuedTokens.getRefreshToken());
+ log.info("다음 refresh token 생성 시간 : {}",time2);
+ Assertions.assertNotEquals(time1, time2);
+ }
+
+ @Test
+ public void when_reissue_then_not_match(){
+ // 토큰 생성
+ issuedTokens = jwtIssuer.getAccessTokenByAuthorityInfo(authorityInfo1);
+ // 토큰 저장
+ jwtIssuer.saveIssuedToken(email, issuedTokens.getRefreshToken());
+ log.info("초기 토큰 : {}", issuedTokens.getRefreshToken());
+ // 해싱된 refresh token 불러오기
+ String savedRefreshToken = refreshTokenCacheService.searchToken(authorityInfo1.getEmail());
+
+ String time1 = getCreatedTime(issuedTokens.getRefreshToken());
+ log.info("초기 refresh token 생성 시간 : {}",time1);
+ // 처음 생성
+ IssuedTokens newIssuedTokens = jwtIssuer.getAccessTokenByRefreshToken(new RefreshDto(issuedTokens.getRefreshToken()));
+ String time2 = getCreatedTime(newIssuedTokens.getRefreshToken());
+ log.info("다음 토큰 : {}", newIssuedTokens.getRefreshToken());
+ log.info("다음 refresh token 생성 시간 : {}",time2);
+
+ Assertions.assertNotEquals(time1, time2);
+ // 새로운 refresh token 가져오고, 해싱된 토큰 비교. 다른 값을 해싱했기 때문에 match하지 말아야한다.
+ Assertions.assertTrue(!tokenHasher.matches(newIssuedTokens.getRefreshToken(), savedRefreshToken));
+ }
+
+ @Test
+ public void when_string_then_not_match_sha_256(){
+ // 토큰 생성
+ String test1 = "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTb2wtS2ltamFuZyIsInN1YiI6IkpXVCBUb2tlbiIsImVtYWlsIjoic29sc29sQGdtYWlsLmNvbSIsImF1dGhvcml0aWVzIjoiUk9MRV9VU0VSIiwiY3JlYXRlX2RhdGUiOiIyMDI0LTA4LTAyVDE3OjMxOjQxLjMzMzkwNCIsImlhdCI6MTcyMjU4NzUwMSwiZXhwIjoxNzIyNTg3NjIxfQ.RYVguGifzq4jQ4fCHfNGTGfFlMLn-VnmMy_BAKPLsEE";
+ String test2 = "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTb2wtS2ltamFuZyIsInN1YiI6IkpXVCBUb2tlbiIsImVtYWlsIjoic29sc29sQGdtYWlsLmNvbSIsImF1dGhvcml0aWVzIjoiUk9MRV9VU0VSIiwiY3JlYXRlX2RhdGUiOiIyMDI0LTA4LTAyVDE3OjMxOjQxLjcwMDE3MyIsImlhdCI6MTcyMjU4NzUwMSwiZXhwIjoxNzIyNTg3NjIxfQ.J_HxlIgceLJTjbU58_KIgfeb8gRiOfmHPBaWnQyXc7w";
+
+ String hashed = tokenHasher.encode(test1);
+ // 새로운 refresh token 가져오고, 해싱된 토큰 비교. 다른 값을 해싱했기 때문에 match하지 말아야한다.
+ Assertions.assertFalse(tokenHasher.matches(test2, hashed));
+ }
+
+// @Test
+// public void when_string_then_not_match_bCrypt(){
+// // 토큰 생성
+// String test1 = jwtIssuer.getRefreshToken(authorityInfo1);
+// log.info("test1 : {}",test1);
+// String test2 = jwtIssuer.getRefreshToken(authorityInfo2);;
+// log.info("test2 : {}",test2);
+//
+// String hashed = bCryptPasswordEncoder.encode(test1);
+// // 새로운 refresh token 가져오고, 해싱된 토큰 비교. 다른 값을 해싱했기 때문에 match하지 말아야한다.
+// Assertions.assertFalse(bCryptPasswordEncoder.matches(test2, hashed));
+// }
+
+
+ @Test
+ public void when_reissue_then_invoke_exception(){
+ // 토큰 생성
+ issuedTokens = jwtIssuer.getAccessTokenByAuthorityInfo(authorityInfo1);
+ // 토큰 저장
+ jwtIssuer.saveIssuedToken(email, issuedTokens.getRefreshToken());
+ String time1 = getCreatedTime(issuedTokens.getRefreshToken());
+ log.info("초기 refresh token 생성 시간 : {}",time1);
+ // 처음 생성
+ IssuedTokens newIssuedTokens = jwtIssuer.getAccessTokenByRefreshToken(new RefreshDto(issuedTokens.getRefreshToken()));
+ String time2 = getCreatedTime(newIssuedTokens.getRefreshToken());
+ log.info("다음 refresh token 생성 시간 : {}",time2);
+
+ Assertions.assertThrows(UnauthorizedException.class,
+ () -> jwtIssuer.getAccessTokenByRefreshToken(new RefreshDto(issuedTokens.getRefreshToken())));
+ }
+
+ private String getCreatedTime(String refreshToken) {
+ Claims claims = Jwts.parser()
+ .verifyWith(key) // 서버가 저장하고 있는 키로 payload 암호 풀기
+ .build()
+ .parseSignedClaims(refreshToken)
+ .getPayload();
+ return (String) claims.get("create_date");
+ }
+}
diff --git a/Backend/src/test/java/kimjang/toolkit/solsol/jwt/RefreshTokenCacheServiceTest.java b/Backend/src/test/java/kimjang/toolkit/solsol/jwt/RefreshTokenCacheServiceTest.java
new file mode 100644
index 0000000..5ea8629
--- /dev/null
+++ b/Backend/src/test/java/kimjang/toolkit/solsol/jwt/RefreshTokenCacheServiceTest.java
@@ -0,0 +1,120 @@
+package kimjang.toolkit.solsol.jwt;
+
+import kimjang.toolkit.solsol.SolsolApplication;
+import kimjang.toolkit.solsol.domain.cache.RefreshToken;
+import kimjang.toolkit.solsol.domain.cache.RefreshTokenCacheService;
+import kimjang.toolkit.solsol.domain.cache.RefreshTokenRepository;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+
+@Slf4j
+@SpringBootTest(classes = SolsolApplication.class)
+@ActiveProfiles(value = "dev")
+public class RefreshTokenCacheServiceTest {
+
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ @Autowired
+ private RefreshTokenCacheService refreshTokenCacheService;
+
+ @Autowired
+ private RefreshTokenRepository refreshTokenRepository;
+
+ @Test
+ public void checkCacheableToken(){
+ String email = "solsol@gmail.com";
+ String refreshToken = "1234";
+ String hashedRefreshToken = passwordEncoder.encode(refreshToken);
+
+ // email에 맞는 refresh token 캐시에 저장
+ refreshTokenCacheService.saveToken(email, hashedRefreshToken);
+ // 캐시에 있는 refresh token 얻어오기
+ String savedRefreshToken = refreshTokenCacheService.searchToken(email);
+ Assertions.assertTrue(passwordEncoder.matches(refreshToken, savedRefreshToken));
+ }
+
+
+
+ private final int testCount = 10000;
+ @Test
+ public void countTimeDBAndCache(){
+ // set up
+ String email = "solsol@gmail.com";
+ String refreshToken = "1234";
+ String hashedRefreshToken = passwordEncoder.encode(refreshToken);
+ RefreshToken tokenEntity = RefreshToken.builder()
+ .email(email)
+ .refreshToken(hashedRefreshToken)
+ .build();
+ refreshTokenRepository.save(tokenEntity);
+ // email에 맞는 refresh token 캐시에 저장
+ refreshTokenCacheService.saveToken(email, hashedRefreshToken);
+
+ LocalDateTime start = LocalDateTime.now();
+ for(int i=0; i