From 88b70ecd8ba959bca46f7125ec129793c5103e72 Mon Sep 17 00:00:00 2001 From: myqewr Date: Mon, 21 Apr 2025 21:38:42 +0900 Subject: [PATCH] =?UTF-8?q?feat=20:=20=EC=84=B8=EC=85=98=20=EC=9C=A0?= =?UTF-8?q?=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20api=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/docs/asciidoc/auth-api.adoc | 20 +++++ .../SessionValidityCheckController.java | 34 +++++++ .../SessionValidityCheckResponse.java | 12 +++ .../security/SecurityConfig.java | 5 +- .../auth/SessionValidationCheckTest.java | 90 +++++++++++++++++++ 5 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/ftm/server/adapter/in/web/auth/controller/SessionValidityCheckController.java create mode 100644 src/main/java/com/ftm/server/adapter/in/web/auth/dto/response/SessionValidityCheckResponse.java create mode 100644 src/test/java/com/ftm/server/auth/SessionValidationCheckTest.java diff --git a/src/docs/asciidoc/auth-api.adoc b/src/docs/asciidoc/auth-api.adoc index 07b80df..1890e27 100644 --- a/src/docs/asciidoc/auth-api.adoc +++ b/src/docs/asciidoc/auth-api.adoc @@ -70,3 +70,23 @@ include::{snippetsDir}/logout/1/response-fields.adoc[] ==== 실패 Response include::{snippetsDir}/logout/2/http-response.adoc[] + + +=== **4. Session 유효성 확인 API** + +Session 유효성 확인 api입니다. + +==== Request +include::{snippetsDir}/sessionValidityCheck/1/http-request.adoc[] + +==== 성공 Response +성공 1. 유효한 경우 +include::{snippetsDir}/sessionValidityCheck/1/http-response.adoc[] + +성공 2. 유효하지 않은 경우 +include::{snippetsDir}/sessionValidityCheck/2/http-response.adoc[] + +==== Response Body Fields +include::{snippetsDir}/sessionValidityCheck/1/response-fields.adoc[] + + diff --git a/src/main/java/com/ftm/server/adapter/in/web/auth/controller/SessionValidityCheckController.java b/src/main/java/com/ftm/server/adapter/in/web/auth/controller/SessionValidityCheckController.java new file mode 100644 index 0000000..a09f42c --- /dev/null +++ b/src/main/java/com/ftm/server/adapter/in/web/auth/controller/SessionValidityCheckController.java @@ -0,0 +1,34 @@ +package com.ftm.server.adapter.in.web.auth.controller; + +import com.ftm.server.adapter.in.web.auth.dto.response.SessionValidityCheckResponse; +import com.ftm.server.common.response.ApiResponse; +import com.ftm.server.common.response.enums.SuccessResponseCode; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class SessionValidityCheckController { + + @GetMapping("/api/auth/session/validity") + public ResponseEntity> sessionValidationCheck( + HttpServletRequest req, HttpServletResponse res) { + + Boolean isValid = true; + + HttpSession session = req.getSession(false); // session 조회 + + if (session == null) { + isValid = false; + } + + return ResponseEntity.status(HttpStatus.OK) + .body( + ApiResponse.success( + SuccessResponseCode.OK, SessionValidityCheckResponse.of(isValid))); + } +} diff --git a/src/main/java/com/ftm/server/adapter/in/web/auth/dto/response/SessionValidityCheckResponse.java b/src/main/java/com/ftm/server/adapter/in/web/auth/dto/response/SessionValidityCheckResponse.java new file mode 100644 index 0000000..e3eca7f --- /dev/null +++ b/src/main/java/com/ftm/server/adapter/in/web/auth/dto/response/SessionValidityCheckResponse.java @@ -0,0 +1,12 @@ +package com.ftm.server.adapter.in.web.auth.dto.response; + +import lombok.Data; + +@Data +public class SessionValidityCheckResponse { + private final Boolean isValid; + + public static SessionValidityCheckResponse of(Boolean isValid) { + return new SessionValidityCheckResponse(isValid); + } +} diff --git a/src/main/java/com/ftm/server/infrastructure/security/SecurityConfig.java b/src/main/java/com/ftm/server/infrastructure/security/SecurityConfig.java index 8d7b643..6199fa4 100644 --- a/src/main/java/com/ftm/server/infrastructure/security/SecurityConfig.java +++ b/src/main/java/com/ftm/server/infrastructure/security/SecurityConfig.java @@ -51,7 +51,10 @@ public class SecurityConfig { "https://fittheman.site"); // 개발 환경 클라이언트 도메인 private static final String[] GET_ANONYMOUS_MATCHERS = { - "/api/users/email/duplication", "/api/users/options", "/api/grooming/tests" + "/api/users/email/duplication", + "/api/users/options", + "/api/grooming/tests", + "/api/auth/session/validity" }; private static final String[] POST_ANONYMOUS_MATCHERS = { diff --git a/src/test/java/com/ftm/server/auth/SessionValidationCheckTest.java b/src/test/java/com/ftm/server/auth/SessionValidationCheckTest.java new file mode 100644 index 0000000..d3f3b2b --- /dev/null +++ b/src/test/java/com/ftm/server/auth/SessionValidationCheckTest.java @@ -0,0 +1,90 @@ +package com.ftm.server.auth; + +import static com.epages.restdocs.apispec.ResourceDocumentation.resource; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.JsonFieldType.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.epages.restdocs.apispec.ResourceSnippetParameters; +import com.ftm.server.BaseTest; +import jakarta.servlet.http.Cookie; +import jakarta.transaction.Transactional; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; +import org.springframework.restdocs.payload.FieldDescriptor; +import org.springframework.test.web.servlet.ResultActions; + +public class SessionValidationCheckTest extends BaseTest { + + private final List responseFieldDescriptors = + List.of( + fieldWithPath("status").type(NUMBER).description("응답 상태"), + fieldWithPath("code").type(STRING).description("상태 코드"), + fieldWithPath("message").type(STRING).description("메시지"), + fieldWithPath("data").type(OBJECT).optional().description("data"), + fieldWithPath("data.isValid").type(BOOLEAN).description("session 유효성 여부")); + + private ResultActions getResultActions(MockHttpSession session) throws Exception { + return mockMvc.perform( // api 실행 + RestDocumentationRequestBuilders.get("/api/auth/session/validity") + .session(session) + .cookie(new Cookie("SESSION", session.getId()))); + } + + private RestDocumentationResultHandler getDocument(Integer identifier) { + return document( + "sessionValidityCheck/" + identifier, + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint(), getModifiedHeader()), + responseFields(responseFieldDescriptors), + resource( + ResourceSnippetParameters.builder() + .tag("인증/인가") + .summary("세션 유효성 확인 api") + .description("세션 유효성 확인 api입니다.") + .responseFields(responseFieldDescriptors) + .build())); + } + + @Test + @Transactional + public void 세션_유효성_성공1() throws Exception { + // given + MockHttpSession session = createUserAndLogin(); + + // when + ResultActions resultActions = getResultActions(session); + + // then + resultActions.andExpect(status().isOk()).andExpect(jsonPath("data.isValid").value(true)); + ; + + // documentation + resultActions.andDo(getDocument(1)); + } + + @Test + @Transactional + public void 세션_유효성_성공2() throws Exception { + // given + MockHttpSession session = createUserAndLogin(); + session.invalidate(); + + // when + ResultActions resultActions = getResultActions(session); + + // then + resultActions.andExpect(status().isOk()).andExpect(jsonPath("data.isValid").value(false)); + + // documentation + resultActions.andDo(getDocument(2)); + } +}