diff --git a/src/test/java/com/yam/app/account/presentation/AccountApiUri.java b/src/main/java/com/yam/app/account/infrastructure/AccountApiUri.java similarity index 61% rename from src/test/java/com/yam/app/account/presentation/AccountApiUri.java rename to src/main/java/com/yam/app/account/infrastructure/AccountApiUri.java index 9ba4a93..7441b98 100644 --- a/src/test/java/com/yam/app/account/presentation/AccountApiUri.java +++ b/src/main/java/com/yam/app/account/infrastructure/AccountApiUri.java @@ -1,10 +1,15 @@ package com.yam.app.account.presentation; -public interface AccountApiUri { +public final class AccountApiUri { String REGISTER = "/api/accounts"; String EMAIL_CONFIRM = "/api/accounts/authorize"; String LOGIN = "/api/accounts/login"; String FIND_INFO = "/api/accounts/me"; + String UNAUTHORIZED_REQUEST = "/api/error/UnauthorizedRequest"; + + private AccountApiUri() { + } + } diff --git a/src/main/java/com/yam/app/account/infrastructure/SessionAuthInterceptor.java b/src/main/java/com/yam/app/account/infrastructure/SessionAuthInterceptor.java new file mode 100644 index 0000000..4ebbd2e --- /dev/null +++ b/src/main/java/com/yam/app/account/infrastructure/SessionAuthInterceptor.java @@ -0,0 +1,31 @@ +package com.yam.app.account.infrastructure; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.web.servlet.HandlerInterceptor; + +public final class SessionAuthInterceptor implements HandlerInterceptor { + + @Override + public boolean preHandle(HttpServletRequest request, + HttpServletResponse response, Object handler) throws Exception { + + var session = request.getSession(false); + + if (session == null) { + request.setAttribute("message", "Unauthorized request"); + request.getRequestDispatcher(AccountApiUri.UNAUTHORIZED_REQUEST) + .forward(request, response); + return false; + } + + if (session.getAttribute(SessionManager.LOGIN_ACCOUNT) == null) { + request.setAttribute("message", "Failed fetch principal"); + request.getRequestDispatcher(AccountApiUri.UNAUTHORIZED_REQUEST) + .forward(request, response); + return false; + } + + return true; + } +} diff --git a/src/main/java/com/yam/app/account/infrastructure/SessionManager.java b/src/main/java/com/yam/app/account/infrastructure/SessionManager.java index 4b221ab..c8d7966 100644 --- a/src/main/java/com/yam/app/account/infrastructure/SessionManager.java +++ b/src/main/java/com/yam/app/account/infrastructure/SessionManager.java @@ -5,7 +5,7 @@ import javax.servlet.http.HttpSession; public final class SessionManager { - private static final String LOGIN_ACCOUNT = "LOGIN_ACCOUNT_EMAIL"; + public static final String LOGIN_ACCOUNT = "LOGIN_ACCOUNT_EMAIL"; private final HttpSession httpSession; diff --git a/src/main/java/com/yam/app/account/infrastructure/WebConfiguration.java b/src/main/java/com/yam/app/account/infrastructure/WebConfiguration.java index 90c4f31..ccb4df1 100644 --- a/src/main/java/com/yam/app/account/infrastructure/WebConfiguration.java +++ b/src/main/java/com/yam/app/account/infrastructure/WebConfiguration.java @@ -3,13 +3,28 @@ package com.yam.app.account.infrastructure; import java.util.List; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfiguration implements WebMvcConfigurer { + private static final String[] EXCLUDE_PATHS = { + AccountApiUri.LOGIN, + AccountApiUri.EMAIL_CONFIRM, + AccountApiUri.REGISTER, + "/api/accounts/error/**" + }; + @Override public void addArgumentResolvers(List resolvers) { resolvers.add(new LoginAccountMethodArgumentResolver()); } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new SessionAuthInterceptor()) + .addPathPatterns("/api/**") + .excludePathPatterns(EXCLUDE_PATHS); + } } diff --git a/src/main/java/com/yam/app/account/presentation/AccountErrorApi.java b/src/main/java/com/yam/app/account/presentation/AccountErrorApi.java new file mode 100644 index 0000000..696c4a5 --- /dev/null +++ b/src/main/java/com/yam/app/account/presentation/AccountErrorApi.java @@ -0,0 +1,25 @@ +package com.yam.app.account.presentation; + +import com.yam.app.account.infrastructure.AccountApiUri; +import com.yam.app.common.UnauthorizedRequestException; +import java.util.Optional; +import javax.servlet.http.HttpServletRequest; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping( + produces = MediaType.APPLICATION_JSON_VALUE, + consumes = MediaType.APPLICATION_JSON_VALUE +) +public final class AccountErrorApi { + + @GetMapping(AccountApiUri.UNAUTHORIZED_REQUEST) + public void apiError(HttpServletRequest request) throws UnauthorizedRequestException { + throw new UnauthorizedRequestException( + Optional.ofNullable((String) request.getAttribute("message")) + .orElse("Unauthorized request")); + } +} diff --git a/src/test/java/com/yam/app/account/integration/AccountIntegrationTests.java b/src/test/java/com/yam/app/account/integration/AccountIntegrationTests.java index 0b951e4..4c20e0a 100644 --- a/src/test/java/com/yam/app/account/integration/AccountIntegrationTests.java +++ b/src/test/java/com/yam/app/account/integration/AccountIntegrationTests.java @@ -1,10 +1,5 @@ package com.yam.app.account.integration; -import static com.yam.app.account.presentation.AccountApiUri.EMAIL_CONFIRM; -import static com.yam.app.account.presentation.AccountApiUri.FIND_INFO; -import static com.yam.app.account.presentation.AccountApiUri.LOGIN; -import static com.yam.app.account.presentation.AccountApiUri.REGISTER; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -13,6 +8,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.setup.SharedHttpSessionConfigurer.sharedHttpSession; import com.fasterxml.jackson.databind.ObjectMapper; +import com.yam.app.account.infrastructure.AccountApiUri; import com.yam.app.account.presentation.LoginAccountCommand; import com.yam.app.account.presentation.RegisterAccountCommand; import org.junit.jupiter.api.BeforeEach; @@ -60,7 +56,7 @@ final class AccountIntegrationTests { command.setPassword("password!"); // Act - final var actions = mockMvc.perform(post(REGISTER) + final var actions = mockMvc.perform(post(AccountApiUri.REGISTER) .accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(command)) diff --git a/src/test/java/com/yam/app/account/presentation/AccountCommandApiTests.java b/src/test/java/com/yam/app/account/presentation/AccountCommandApiTests.java index 283bc4b..971913c 100644 --- a/src/test/java/com/yam/app/account/presentation/AccountCommandApiTests.java +++ b/src/test/java/com/yam/app/account/presentation/AccountCommandApiTests.java @@ -1,8 +1,8 @@ package com.yam.app.account.presentation; -import static com.yam.app.account.presentation.AccountApiUri.EMAIL_CONFIRM; -import static com.yam.app.account.presentation.AccountApiUri.LOGIN; -import static com.yam.app.account.presentation.AccountApiUri.REGISTER; +import static com.yam.app.account.infrastructure.AccountApiUri.EMAIL_CONFIRM; +import static com.yam.app.account.infrastructure.AccountApiUri.LOGIN; +import static com.yam.app.account.infrastructure.AccountApiUri.REGISTER; import static org.mockito.Mockito.doThrow; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -37,6 +37,14 @@ final class AccountCommandApiTests { @MockBean private AccountFacade accountFacade; + private void assertThatInvalidArgumentError(ResultActions actions) throws Exception { + actions + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.success").value(false)) + .andExpect(jsonPath("$.data").doesNotExist()) + .andExpect(jsonPath("$.message").value("Invalid argument")); + } + @Nested @DisplayName("로그인 HTTP API") class LoginApi { @@ -265,12 +273,4 @@ final class AccountCommandApiTests { } - private void assertThatInvalidArgumentError(ResultActions actions) throws Exception { - actions - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.success").value(false)) - .andExpect(jsonPath("$.data").doesNotExist()) - .andExpect(jsonPath("$.message").value("Invalid argument")); - } - } diff --git a/src/test/java/com/yam/app/account/presentation/AccountQueryApiTest.java b/src/test/java/com/yam/app/account/presentation/AccountQueryApiTest.java index 72b03f1..b81b6d1 100644 --- a/src/test/java/com/yam/app/account/presentation/AccountQueryApiTest.java +++ b/src/test/java/com/yam/app/account/presentation/AccountQueryApiTest.java @@ -1,6 +1,6 @@ package com.yam.app.account.presentation; -import static com.yam.app.account.presentation.AccountApiUri.FIND_INFO; +import static com.yam.app.account.infrastructure.AccountApiUri.FIND_INFO; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -9,6 +9,8 @@ import com.yam.app.account.application.AccountFacade; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -25,6 +27,22 @@ class AccountQueryApiTest { @MockBean private AccountFacade accountFacade; + @ParameterizedTest + @ValueSource(strings = {FIND_INFO}) + @DisplayName("로그인을 하지 않은 경우 인증이 필요한 다른 URI 에 접근할 수 없다.") + void no_current_session_account_request(String uri) throws Exception { + //Act + final var actions = mockMvc.perform(get(uri) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON)); + + //Assert + actions + .andExpect(status().isUnauthorized()) + .andExpect(jsonPath("$.success").value(false)) + .andExpect(jsonPath("$.data").doesNotExist()); + } + @Nested @DisplayName("사용자 조회 HTTP API") class LoginApi {