diff --git a/refrigerator/.idea/modules/refrigerator.main.iml b/refrigerator/.idea/modules/refrigerator.main.iml
index ac8e328..397c268 100644
--- a/refrigerator/.idea/modules/refrigerator.main.iml
+++ b/refrigerator/.idea/modules/refrigerator.main.iml
@@ -1,6 +1,9 @@
+
+
+
@@ -17,5 +20,4 @@
-
-
+
\ No newline at end of file
diff --git a/refrigerator/src/main/java/moja/refrigerator/aggregate/user/TokenBlacklist.java b/refrigerator/src/main/java/moja/refrigerator/aggregate/user/TokenBlacklist.java
new file mode 100644
index 0000000..fc72650
--- /dev/null
+++ b/refrigerator/src/main/java/moja/refrigerator/aggregate/user/TokenBlacklist.java
@@ -0,0 +1,16 @@
+package moja.refrigerator.aggregate.user;
+
+import jakarta.persistence.*;
+import lombok.Data;
+
+@Entity
+@Table(name = "tbl_token_blacklist")
+@Data
+public class TokenBlacklist {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long blacklistPk;
+
+ @Column(nullable = false)
+ private String blacklistToken;
+}
diff --git a/refrigerator/src/main/java/moja/refrigerator/config/SecurityConfig.java b/refrigerator/src/main/java/moja/refrigerator/config/SecurityConfig.java
index 462533f..f42e6c7 100644
--- a/refrigerator/src/main/java/moja/refrigerator/config/SecurityConfig.java
+++ b/refrigerator/src/main/java/moja/refrigerator/config/SecurityConfig.java
@@ -1,8 +1,11 @@
package moja.refrigerator.config;
+import jakarta.servlet.http.HttpServletResponse;
import moja.refrigerator.jwt.JWTFilter;
import moja.refrigerator.jwt.JWTUtil;
import moja.refrigerator.jwt.LoginFilter;
+import moja.refrigerator.jwt.LogoutFilter;
+import moja.refrigerator.repository.user.TokenBlacklistRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
@@ -21,10 +24,14 @@ public class SecurityConfig {
private final AuthenticationConfiguration authenticationConfiguration;
// JWTUtil 주입
private final JWTUtil jwtUtil;
+ private final LogoutFilter logoutFilter;
+ private final TokenBlacklistRepository tokenBlacklistRepository;
- public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JWTUtil jwtUtil) {
+ public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JWTUtil jwtUtil, LogoutFilter logoutFilter, TokenBlacklistRepository tokenBlacklistRepository) {
this.authenticationConfiguration = authenticationConfiguration;
this.jwtUtil = jwtUtil;
+ this.logoutFilter = logoutFilter;
+ this.tokenBlacklistRepository = tokenBlacklistRepository;
}
@Bean
@@ -66,11 +73,22 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); // JWT 사용을 위한 세션리스 설정
// 로그인 필터 추가
- http
- .addFilterBefore(new JWTFilter(jwtUtil), LoginFilter.class);
http
.addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil), UsernamePasswordAuthenticationFilter.class);
+ http
+ .addFilterAfter(new JWTFilter(jwtUtil, tokenBlacklistRepository), LoginFilter.class);
+
+ http
+ .logout(logout -> logout
+ .logoutUrl("/logout")
+ .addLogoutHandler(logoutFilter)
+ .logoutSuccessHandler((request, response, authentication) -> {
+ response.setContentType("application/json;charset=UTF-8");
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.getWriter().write("로그아웃 되었습니다.");
+ }));
+
return http.build();
}
}
\ No newline at end of file
diff --git a/refrigerator/src/main/java/moja/refrigerator/controller/user/UserController.java b/refrigerator/src/main/java/moja/refrigerator/controller/user/UserController.java
index 7adacab..97692a3 100644
--- a/refrigerator/src/main/java/moja/refrigerator/controller/user/UserController.java
+++ b/refrigerator/src/main/java/moja/refrigerator/controller/user/UserController.java
@@ -1,7 +1,9 @@
package moja.refrigerator.controller.user;
+import jakarta.servlet.http.HttpServletRequest;
import moja.refrigerator.dto.user.request.UserCreateRequest;
import moja.refrigerator.service.user.UserService;
+import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -23,7 +25,8 @@ public String getMainPage() {
// 회원 가입 처리
@PostMapping("/auth/join")
- public void joinProcess(@RequestBody UserCreateRequest request) {
+ public ResponseEntity> join(@RequestBody UserCreateRequest request) {
userService.createUser(request);
+ return ResponseEntity.ok().body("회원가입이 완료되었습니다.");
}
}
diff --git a/refrigerator/src/main/java/moja/refrigerator/jwt/JWTFilter.java b/refrigerator/src/main/java/moja/refrigerator/jwt/JWTFilter.java
index e22cfe8..a0b4677 100644
--- a/refrigerator/src/main/java/moja/refrigerator/jwt/JWTFilter.java
+++ b/refrigerator/src/main/java/moja/refrigerator/jwt/JWTFilter.java
@@ -6,6 +6,7 @@
import jakarta.servlet.http.HttpServletResponse;
import moja.refrigerator.aggregate.user.User;
import moja.refrigerator.dto.user.CustomUserDetails;
+import moja.refrigerator.repository.user.TokenBlacklistRepository;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -15,9 +16,11 @@
public class JWTFilter extends OncePerRequestFilter {
private final JWTUtil jwtUtil;
+ private final TokenBlacklistRepository tokenBlacklistRepository;
- public JWTFilter(JWTUtil jwtUtil) {
+ public JWTFilter(JWTUtil jwtUtil, TokenBlacklistRepository tokenBlacklistRepository) {
this.jwtUtil = jwtUtil;
+ this.tokenBlacklistRepository = tokenBlacklistRepository;
}
@Override
@@ -33,6 +36,12 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
String token = authorization.split(" ")[1];
+ // 블랙리스트 체크
+ if (tokenBlacklistRepository.existsByBlacklistToken(token)) {
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ return;
+ }
+
// 토큰 소멸 시간 검증
if (jwtUtil.isExpired(token)) {
// 만료된 토큰이면 그냥 통과
diff --git a/refrigerator/src/main/java/moja/refrigerator/jwt/LogoutFilter.java b/refrigerator/src/main/java/moja/refrigerator/jwt/LogoutFilter.java
new file mode 100644
index 0000000..971f73d
--- /dev/null
+++ b/refrigerator/src/main/java/moja/refrigerator/jwt/LogoutFilter.java
@@ -0,0 +1,34 @@
+package moja.refrigerator.jwt;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import moja.refrigerator.aggregate.user.TokenBlacklist;
+import moja.refrigerator.repository.user.TokenBlacklistRepository;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.logout.LogoutHandler;
+import org.springframework.stereotype.Component;
+
+@Component
+public class LogoutFilter implements LogoutHandler {
+ private final TokenBlacklistRepository tokenBlacklistRepository;
+
+ public LogoutFilter(TokenBlacklistRepository tokenBlacklistRepository) {
+ this.tokenBlacklistRepository = tokenBlacklistRepository;
+ }
+
+ @Override
+ public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
+ String authorization = request.getHeader("Authorization");
+
+ if (authorization == null || !authorization.startsWith("Bearer ")) {
+ throw new IllegalArgumentException("토큰이 유효하지 않습니다.");
+ }
+
+ String token = authorization.split(" ")[1];
+
+ // 토큰을 블랙리스트에 추가
+ TokenBlacklist blacklist = new TokenBlacklist();
+ blacklist.setBlacklistToken(token);
+ tokenBlacklistRepository.save(blacklist);
+ }
+}
diff --git a/refrigerator/src/main/java/moja/refrigerator/repository/user/TokenBlacklistRepository.java b/refrigerator/src/main/java/moja/refrigerator/repository/user/TokenBlacklistRepository.java
new file mode 100644
index 0000000..6d82bd7
--- /dev/null
+++ b/refrigerator/src/main/java/moja/refrigerator/repository/user/TokenBlacklistRepository.java
@@ -0,0 +1,8 @@
+package moja.refrigerator.repository.user;
+
+import moja.refrigerator.aggregate.user.TokenBlacklist;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface TokenBlacklistRepository extends JpaRepository {
+ boolean existsByBlacklistToken(String blacklistToken);
+}
diff --git a/refrigerator/src/main/java/moja/refrigerator/service/user/UserService.java b/refrigerator/src/main/java/moja/refrigerator/service/user/UserService.java
index 80fa52c..a3cc1fa 100644
--- a/refrigerator/src/main/java/moja/refrigerator/service/user/UserService.java
+++ b/refrigerator/src/main/java/moja/refrigerator/service/user/UserService.java
@@ -1,5 +1,6 @@
package moja.refrigerator.service.user;
+import jakarta.servlet.http.HttpServletRequest;
import moja.refrigerator.dto.user.request.UserCreateRequest;
public interface UserService {
diff --git a/refrigerator/src/main/java/moja/refrigerator/service/user/UserServiceImpl.java b/refrigerator/src/main/java/moja/refrigerator/service/user/UserServiceImpl.java
index 7cd888b..0bbb720 100644
--- a/refrigerator/src/main/java/moja/refrigerator/service/user/UserServiceImpl.java
+++ b/refrigerator/src/main/java/moja/refrigerator/service/user/UserServiceImpl.java
@@ -1,8 +1,11 @@
package moja.refrigerator.service.user;
+import jakarta.servlet.http.HttpServletRequest;
+import moja.refrigerator.aggregate.user.TokenBlacklist;
import moja.refrigerator.aggregate.user.User;
import moja.refrigerator.dto.user.request.UserCreateRequest;
import moja.refrigerator.exception.user.DuplicateUserException;
+import moja.refrigerator.repository.user.TokenBlacklistRepository;
import moja.refrigerator.repository.user.UserRepository;
import org.modelmapper.ModelMapper;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@@ -17,11 +20,13 @@ public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final BCryptPasswordEncoder passwordEncoder;
private final ModelMapper modelMapper;
+ private final TokenBlacklistRepository tokenBlacklistRepository;
- public UserServiceImpl(UserRepository userRepository, BCryptPasswordEncoder passwordEncoder, ModelMapper modelMapper) {
+ public UserServiceImpl(UserRepository userRepository, BCryptPasswordEncoder passwordEncoder, ModelMapper modelMapper, TokenBlacklistRepository tokenBlacklistRepository) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
this.modelMapper = modelMapper;
+ this.tokenBlacklistRepository = tokenBlacklistRepository;
}
@Override
@@ -40,7 +45,6 @@ public void createUser(UserCreateRequest request) {
userRepository.save(user);
}
-
private void checkDuplicateUser(UserCreateRequest request) {
List errors = new ArrayList<>();
if (userRepository.existsByUserId(request.getUserId())) {