diff --git a/src/main/java/com/sb/web/common/config/WebConfig.java b/src/main/java/com/sb/web/common/config/WebConfig.java index f179ada..f36fc5a 100644 --- a/src/main/java/com/sb/web/common/config/WebConfig.java +++ b/src/main/java/com/sb/web/common/config/WebConfig.java @@ -24,6 +24,7 @@ public class WebConfig implements WebMvcConfigurer { // 인증: 로그인 필요한 경로 (관리자 경로 포함 — SessionUser 세팅용으로 먼저 실행) registry.addInterceptor(authInterceptor) .addPathPatterns("/api/auth/me", "/api/auth/logout", "/api/auth/password", + "/api/auth/verify-password", "/api/auth/profile", "/api/board/**", "/api/admin/**", "/api/account/**"); // 인가: 관리자 전용 경로 (authInterceptor 다음에 실행되어 role 검사) registry.addInterceptor(adminInterceptor) diff --git a/src/test/java/com/sb/web/common/config/WebConfigTest.java b/src/test/java/com/sb/web/common/config/WebConfigTest.java new file mode 100644 index 0000000..bf62607 --- /dev/null +++ b/src/test/java/com/sb/web/common/config/WebConfigTest.java @@ -0,0 +1,51 @@ +package com.sb.web.common.config; + +import com.sb.web.auth.web.AdminInterceptor; +import com.sb.web.auth.web.AuthInterceptor; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.springframework.web.servlet.config.annotation.InterceptorRegistration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * 인터셉터 보호 경로 등록 회귀 가드. + * CURRENT_MEMBER 를 쓰는 인증 필수 엔드포인트가 authInterceptor 경로에 빠지면 + * 인터셉터가 동작하지 않아 로그인 사용자도 NPE(500)가 난다. (verify-password/profile 누락 사례) + */ +class WebConfigTest { + + @Test + @DisplayName("인증 필수 auth 엔드포인트가 모두 보호 경로에 등록된다") + void protectsAuthEndpoints() { + InterceptorRegistry registry = mock(InterceptorRegistry.class); + InterceptorRegistration registration = mock(InterceptorRegistration.class); + when(registry.addInterceptor(any())).thenReturn(registration); + when(registration.addPathPatterns(any(String[].class))).thenReturn(registration); + + new WebConfig(mock(AuthInterceptor.class), mock(AdminInterceptor.class)).addInterceptors(registry); + + ArgumentCaptor captor = ArgumentCaptor.forClass(String[].class); + verify(registration, atLeastOnce()).addPathPatterns(captor.capture()); + + List allPatterns = new ArrayList<>(); + captor.getAllValues().forEach(arr -> allPatterns.addAll(List.of(arr))); + + assertThat(allPatterns).contains( + "/api/auth/me", + "/api/auth/logout", + "/api/auth/password", + "/api/auth/verify-password", + "/api/auth/profile"); + } +}