From 41b405f091a9496efdcc25aa3b85d32d5bf3a815 Mon Sep 17 00:00:00 2001 From: seonjuuu Date: Sun, 11 May 2025 02:22:47 +0900 Subject: [PATCH 1/4] =?UTF-8?q?[feat]=20feat:=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EB=B3=B4=EC=95=88=20=EA=B0=95=ED=99=94=20=EB=B0=8F=20=EB=A7=8C?= =?UTF-8?q?=EB=A3=8C=20=EC=8B=9C=20401=20=EC=9D=91=EB=8B=B5=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../User/config/SessionCheckFilterConfig.java | 19 +++++++++ .../exception/GlobalExceptionHandler.java | 1 + .../User/filter/SessionCheckFilter.java | 40 +++++++++++++++++++ .../pirocheck/User/service/UserService.java | 4 +- .../src/main/resources/application.yml | 10 ++++- 5 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 backend/pirocheck/src/main/java/backend/pirocheck/User/config/SessionCheckFilterConfig.java create mode 100644 backend/pirocheck/src/main/java/backend/pirocheck/User/filter/SessionCheckFilter.java diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/User/config/SessionCheckFilterConfig.java b/backend/pirocheck/src/main/java/backend/pirocheck/User/config/SessionCheckFilterConfig.java new file mode 100644 index 0000000..e5a2556 --- /dev/null +++ b/backend/pirocheck/src/main/java/backend/pirocheck/User/config/SessionCheckFilterConfig.java @@ -0,0 +1,19 @@ +package backend.pirocheck.User.config; + +import backend.pirocheck.User.filter.SessionCheckFilter; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SessionCheckFilterConfig { + + @Bean + public FilterRegistrationBean sessionCheckFilter() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new SessionCheckFilter()); + registrationBean.addUrlPatterns("/api/*"); + registrationBean.setOrder(1); + return registrationBean; + } +} diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/User/exception/GlobalExceptionHandler.java b/backend/pirocheck/src/main/java/backend/pirocheck/User/exception/GlobalExceptionHandler.java index a135034..4fd3755 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/User/exception/GlobalExceptionHandler.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/User/exception/GlobalExceptionHandler.java @@ -9,6 +9,7 @@ @RestControllerAdvice public class GlobalExceptionHandler { + // InvalidLoginException (로그인 실패) @ExceptionHandler(InvalidLoginException.class) public ResponseEntity> handleInvalidLoginException(InvalidLoginException e) { return ResponseEntity diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/User/filter/SessionCheckFilter.java b/backend/pirocheck/src/main/java/backend/pirocheck/User/filter/SessionCheckFilter.java new file mode 100644 index 0000000..61a09c4 --- /dev/null +++ b/backend/pirocheck/src/main/java/backend/pirocheck/User/filter/SessionCheckFilter.java @@ -0,0 +1,40 @@ +package backend.pirocheck.User.filter; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +public class SessionCheckFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, + HttpServletResponse response, + FilterChain filterChain) + throws ServletException, IOException { + + String path = request.getRequestURI(); + + // 로그인/로그아웃 요청은 세션 체크 제외 + if (path.startsWith("/api/login") || path.startsWith("/api/logout")) { + filterChain.doFilter(request, response); // 다음 필터나 컨트롤러로 넘기는 명령어 + return; // 세션 검사 안함 + } + + HttpSession session = request.getSession(false); // 세션이 없으면 새로 만들지 않고 null을 리턴 (true : 새로 생성) + + if (session == null || session.getAttribute("loginUser") == null) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401 설정 + response.setContentType("application/json;charset=UTF-8"); + response.getWriter().write("{\"success\":false,\"message\":\"세션이 만료되었습니다.\",\"data\":null}"); + return; + } + + filterChain.doFilter(request, response); + + } +} diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/User/service/UserService.java b/backend/pirocheck/src/main/java/backend/pirocheck/User/service/UserService.java index 04231cf..ff5fb5d 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/User/service/UserService.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/User/service/UserService.java @@ -14,10 +14,10 @@ public class UserService { public User login(String name, String password) { User user = userRepository.findByName(name) - .orElseThrow(() -> new InvalidLoginException("해당 사용자가 존재하지 않습니다.")); + .orElseThrow(() -> new InvalidLoginException("해당 사용자가 존재하지 않습니다.")); //401 if (!user.getPassword().equals(password)) { - throw new InvalidLoginException("비밀번호가 일치하지 않습니다."); + throw new InvalidLoginException("비밀번호가 일치하지 않습니다."); //401 } return user; diff --git a/backend/pirocheck/src/main/resources/application.yml b/backend/pirocheck/src/main/resources/application.yml index 1416bb4..11c027f 100644 --- a/backend/pirocheck/src/main/resources/application.yml +++ b/backend/pirocheck/src/main/resources/application.yml @@ -11,4 +11,12 @@ spring: properties: hibernate: format_sql: true - open-in-view: false \ No newline at end of file + open-in-view: false +server: + servlet: + session: + cookie: + http-only: true # 세션 쿠키를 HttpOnly로 설정 (JS에서 접근 불가) + secure: false # HTTPS 전용 전송 (Https -> true로 바꿔야 함) + same-site: Lax # CSRF 방지 + timeout: 30m # 세션 타임아웃 30분 (30 minutes) \ No newline at end of file From 807cf52324ffd6d46be5f83426d4559daf730839 Mon Sep 17 00:00:00 2001 From: seonjuuu Date: Sun, 11 May 2025 22:43:12 +0900 Subject: [PATCH 2/4] [feat] WebConfig --- .../pirocheck/User/config/WebConfig.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 backend/pirocheck/src/main/java/backend/pirocheck/User/config/WebConfig.java diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/User/config/WebConfig.java b/backend/pirocheck/src/main/java/backend/pirocheck/User/config/WebConfig.java new file mode 100644 index 0000000..c183098 --- /dev/null +++ b/backend/pirocheck/src/main/java/backend/pirocheck/User/config/WebConfig.java @@ -0,0 +1,17 @@ +package backend.pirocheck.User.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/api/**") // 백엔드 API 요청에만 CORS 허용 + .allowedOrigins("http://pirocheck.org") // 프론트 배포 URL + .allowedMethods("GET", "POST", "PUT", "DELETE") // 허용할 HTTP 메서드 + .allowCredentials(true); // 세션 쿠키 주고받기 허용 + } +} From 8c246912ca756f3584444f3e71ed705bfe9949b6 Mon Sep 17 00:00:00 2001 From: l-wanderer01 Date: Sun, 11 May 2025 22:59:11 +0900 Subject: [PATCH 3/4] =?UTF-8?q?[fix]=20React=EC=99=80=20=EC=97=B0=EA=B2=B0?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pirocheck/{User => }/config/SessionCheckFilterConfig.java | 2 +- .../java/backend/pirocheck/{User => }/config/WebConfig.java | 4 ++-- backend/pirocheck/src/main/resources/application.yml | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) rename backend/pirocheck/src/main/java/backend/pirocheck/{User => }/config/SessionCheckFilterConfig.java (94%) rename backend/pirocheck/src/main/java/backend/pirocheck/{User => }/config/WebConfig.java (83%) diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/User/config/SessionCheckFilterConfig.java b/backend/pirocheck/src/main/java/backend/pirocheck/config/SessionCheckFilterConfig.java similarity index 94% rename from backend/pirocheck/src/main/java/backend/pirocheck/User/config/SessionCheckFilterConfig.java rename to backend/pirocheck/src/main/java/backend/pirocheck/config/SessionCheckFilterConfig.java index e5a2556..06e1edf 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/User/config/SessionCheckFilterConfig.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/config/SessionCheckFilterConfig.java @@ -1,4 +1,4 @@ -package backend.pirocheck.User.config; +package backend.pirocheck.config; import backend.pirocheck.User.filter.SessionCheckFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/User/config/WebConfig.java b/backend/pirocheck/src/main/java/backend/pirocheck/config/WebConfig.java similarity index 83% rename from backend/pirocheck/src/main/java/backend/pirocheck/User/config/WebConfig.java rename to backend/pirocheck/src/main/java/backend/pirocheck/config/WebConfig.java index c183098..a6ae980 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/User/config/WebConfig.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/config/WebConfig.java @@ -1,4 +1,4 @@ -package backend.pirocheck.User.config; +package backend.pirocheck.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; @@ -10,7 +10,7 @@ public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") // 백엔드 API 요청에만 CORS 허용 - .allowedOrigins("http://pirocheck.org") // 프론트 배포 URL + .allowedOrigins("http://pirocheck.org:3000") // 프론트 배포 URL .allowedMethods("GET", "POST", "PUT", "DELETE") // 허용할 HTTP 메서드 .allowCredentials(true); // 세션 쿠키 주고받기 허용 } diff --git a/backend/pirocheck/src/main/resources/application.yml b/backend/pirocheck/src/main/resources/application.yml index 11c027f..b8b7096 100644 --- a/backend/pirocheck/src/main/resources/application.yml +++ b/backend/pirocheck/src/main/resources/application.yml @@ -19,4 +19,5 @@ server: http-only: true # 세션 쿠키를 HttpOnly로 설정 (JS에서 접근 불가) secure: false # HTTPS 전용 전송 (Https -> true로 바꿔야 함) same-site: Lax # CSRF 방지 - timeout: 30m # 세션 타임아웃 30분 (30 minutes) \ No newline at end of file + timeout: 30m # 세션 타임아웃 30분 (30 minutes) + address: 0.0.0.0 \ No newline at end of file From a65944631427da6effadf53474df77db424018fc Mon Sep 17 00:00:00 2001 From: qkrxogmla Date: Sun, 11 May 2025 23:17:08 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=EB=B3=B4=EC=A6=9D=EA=B8=88=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20withCredentials:=20true=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/Deposit.jsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/Deposit.jsx b/frontend/src/Deposit.jsx index ce2198c..500de27 100644 --- a/frontend/src/Deposit.jsx +++ b/frontend/src/Deposit.jsx @@ -5,6 +5,7 @@ import { useEffect, useState } from "react"; const Deposit = () => { const [deposit, setDeposit] = useState(null); + useEffect(() => { const user = JSON.parse(localStorage.getItem("user")); const userId = user?.id; @@ -12,7 +13,9 @@ const Deposit = () => { if (!userId) return; axios - .get(`/api/deposit/${userId}`) + .get(`/api/deposit/${userId}`, { + withCredentials: true, // 세션 쿠키 포함 + }) .then((res) => setDeposit(res.data)) .catch((err) => { alert("보증금 정보를 불러오지 못했습니다.");