From c8bbc54cdf936c475394e994a1017f8fa42519b2 Mon Sep 17 00:00:00 2001 From: taehyun Date: Sat, 7 Jun 2025 21:02:20 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[fix]=20=EA=B6=8C=ED=95=9C=20=EC=A0=95?= =?UTF-8?q?=EC=B1=85=20=EB=B0=98=EC=98=81=EC=9D=84=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?requestMatcher=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../github/petty/config/SecurityConfig.java | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/github/petty/config/SecurityConfig.java b/src/main/java/io/github/petty/config/SecurityConfig.java index 38e192f..99bcb0c 100644 --- a/src/main/java/io/github/petty/config/SecurityConfig.java +++ b/src/main/java/io/github/petty/config/SecurityConfig.java @@ -1,5 +1,6 @@ package io.github.petty.config; +import com.fasterxml.jackson.databind.ObjectMapper; import io.github.petty.users.jwt.JWTFilter; import io.github.petty.users.jwt.JWTUtil; import io.github.petty.users.jwt.LoginFilter; @@ -8,8 +9,10 @@ import io.github.petty.users.repository.UsersRepository; import io.github.petty.users.service.RefreshTokenService; import io.github.petty.users.util.CookieUtils; +import jakarta.servlet.http.HttpServletResponse; 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.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -19,6 +22,9 @@ import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import java.time.LocalDateTime; +import java.util.Map; + @Configuration @EnableWebSecurity public class SecurityConfig { @@ -65,12 +71,45 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .formLogin(form -> form.disable()) .httpBasic(basic -> basic.disable()) .authorizeHttpRequests((auth) -> auth - .requestMatchers("/admin").hasRole("ADMIN") - .requestMatchers("/user").authenticated() - .requestMatchers("/vision/**").authenticated() + // 관리자 전용 + .requestMatchers("/admin/**").hasRole("ADMIN") + .requestMatchers("/api/posts/update-counts").hasRole("ADMIN") + .requestMatchers("/manual-sync/**", "/embedding-batch/**").hasRole("ADMIN") + + // 인증 필요 페이지 + .requestMatchers("/profile/**").authenticated() + .requestMatchers("/posts/detail", "/posts/*/new", "/posts/*/edit").authenticated() .requestMatchers("/flow/**").authenticated() - .requestMatchers("/login/**", "/oauth2/**", "/api/auth/refresh").permitAll() + + // 인증 필요 + .requestMatchers(HttpMethod.POST, "/api/posts").authenticated() + .requestMatchers(HttpMethod.PUT, "/api/posts/**").authenticated() + .requestMatchers(HttpMethod.DELETE, "/api/posts/**").authenticated() + .requestMatchers(HttpMethod.POST, "/api/posts/{id}/comments").authenticated() + .requestMatchers(HttpMethod.PUT, "/api/comments/**").authenticated() + .requestMatchers(HttpMethod.DELETE, "/api/comments/**").authenticated() + .requestMatchers(HttpMethod.POST, "/api/posts/{id}/like").authenticated() + .requestMatchers("/api/images/**").authenticated() + .requestMatchers("/api/users/me", "/api/check-displayname").authenticated() + + // 기본 정책 .anyRequest().permitAll()) + .exceptionHandling(ex -> ex + .authenticationEntryPoint((request, response, authException) -> { + String requestURI = request.getRequestURI(); + + if (requestURI.startsWith("/api/")) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setContentType("application/json;charset=UTF-8"); + + ObjectMapper mapper = new ObjectMapper(); + Map errorResponse = Map.of("error", "로그인이 필요합니다"); + + response.getWriter().write(mapper.writeValueAsString(errorResponse)); + } else { + response.sendRedirect("/login"); + } + })) .oauth2Login(oauth2 -> oauth2 .loginPage("/login") .userInfoEndpoint(userInfo -> userInfo From 96eb7e138681e64cea0da324bc42ad89933e7cf7 Mon Sep 17 00:00:00 2001 From: taehyun Date: Sat, 7 Jun 2025 21:18:27 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[feat]=20404=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/templates/error/404.html | 204 ++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 src/main/resources/templates/error/404.html diff --git a/src/main/resources/templates/error/404.html b/src/main/resources/templates/error/404.html new file mode 100644 index 0000000..8da0d7d --- /dev/null +++ b/src/main/resources/templates/error/404.html @@ -0,0 +1,204 @@ + + + + 페이지를 찾을 수 없습니다 + + + + + + +
+
+
404
+

페이지를 찾을 수 없습니다

+
🐕‍🦺 🔍
+

+ 앗! 우리 반려동물이 길을 잃었나봐요.
+ 요청하신 페이지를 찾을 수 없습니다. +

+
+
+
+ + + + + + \ No newline at end of file From 7505ee1b18203205e08ae23b48a823f3a3a6622c Mon Sep 17 00:00:00 2001 From: taehyun Date: Sat, 7 Jun 2025 22:20:18 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[feat]=20/users/me=20API=EC=97=90=EC=84=9C?= =?UTF-8?q?=20displayName=20=EB=B0=98=ED=99=98=ED=95=98=EB=8F=84=EB=A1=9D?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../petty/users/controller/UsersApiController.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/github/petty/users/controller/UsersApiController.java b/src/main/java/io/github/petty/users/controller/UsersApiController.java index 4e5206f..34f43d6 100644 --- a/src/main/java/io/github/petty/users/controller/UsersApiController.java +++ b/src/main/java/io/github/petty/users/controller/UsersApiController.java @@ -3,7 +3,9 @@ import io.github.petty.users.dto.EmailVerificationRequest; import io.github.petty.users.dto.RefreshTokenResponseDTO; import io.github.petty.users.dto.VerifyCodeRequest; +import io.github.petty.users.entity.Users; import io.github.petty.users.jwt.JWTUtil; +import io.github.petty.users.repository.UsersRepository; import io.github.petty.users.service.EmailService; import io.github.petty.users.service.RefreshTokenService; import io.github.petty.users.service.UserService; @@ -29,13 +31,15 @@ public class UsersApiController { private final EmailService emailService; private final RefreshTokenService refreshTokenService; private final CookieUtils cookieUtils; + private final UsersRepository usersRepository; - public UsersApiController(JWTUtil jwtUtil, EmailService emailService, RefreshTokenService refreshTokenService, UserService userService, CookieUtils cookieUtils) { + public UsersApiController(JWTUtil jwtUtil, EmailService emailService, RefreshTokenService refreshTokenService, UserService userService, CookieUtils cookieUtils, UsersRepository usersRepository) { this.jwtUtil = jwtUtil; this.userService = userService; this.emailService = emailService; this.refreshTokenService = refreshTokenService; this.cookieUtils = cookieUtils; + this.usersRepository = usersRepository; } @GetMapping("/users/me") @@ -46,8 +50,11 @@ public ResponseEntity> getUserInfo() { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } + Users user = usersRepository.findByUsername(auth.getName()); + Map userInfo = new HashMap<>(); - userInfo.put("username", auth.getName()); + // TODO: 프론트엔드에서 username 키로 displayName을 사용 중(키 이름 정리 필요) + userInfo.put("username", user.getDisplayName()); userInfo.put("role", auth.getAuthorities().iterator().next().getAuthority()); return ResponseEntity.ok(userInfo);