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 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); 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