From a6ecd4e2293b3e4225278387de10d742fa3a974f Mon Sep 17 00:00:00 2001 From: Jo In Hyeok Date: Fri, 26 Jul 2024 14:13:57 +0900 Subject: [PATCH] =?UTF-8?q?Feat(*):=20=EA=B0=9C=EB=B0=9C=EC=9A=A9=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EA=B5=AC=ED=98=84=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Feat(*): 개발용 로그인 구현 * Fix(*): exception 오타 수정 --- jabiseo-api/build.gradle | 2 + .../auth/application/DevLoginHelper.java | 33 ++++++++++ .../auth/controller/DevAuthController.java | 39 ++++++++++++ .../exception/GlobalExceptionHandler.java | 22 +++++-- .../controller/DevAuthControllerTest.java | 62 +++++++++++++++++++ .../jabiseo/exception/CommonErrorCode.java | 8 +-- .../java/com/jabiseo/exception/ErrorCode.java | 2 + 7 files changed, 160 insertions(+), 8 deletions(-) create mode 100644 jabiseo-api/src/main/java/com/jabiseo/auth/application/DevLoginHelper.java create mode 100644 jabiseo-api/src/main/java/com/jabiseo/auth/controller/DevAuthController.java create mode 100644 jabiseo-api/src/test/java/com/jabiseo/auth/controller/DevAuthControllerTest.java diff --git a/jabiseo-api/build.gradle b/jabiseo-api/build.gradle index 85e54dd..31fb413 100644 --- a/jabiseo-api/build.gradle +++ b/jabiseo-api/build.gradle @@ -25,4 +25,6 @@ dependencies { implementation 'io.jsonwebtoken:jjwt-api:0.11.2' runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.2' + + testImplementation 'org.springframework.security:spring-security-test' } diff --git a/jabiseo-api/src/main/java/com/jabiseo/auth/application/DevLoginHelper.java b/jabiseo-api/src/main/java/com/jabiseo/auth/application/DevLoginHelper.java new file mode 100644 index 0000000..5b290db --- /dev/null +++ b/jabiseo-api/src/main/java/com/jabiseo/auth/application/DevLoginHelper.java @@ -0,0 +1,33 @@ +package com.jabiseo.auth.application; + + +import com.jabiseo.auth.dto.LoginResponse; +import com.jabiseo.cache.RedisCacheRepository; +import com.jabiseo.member.domain.Member; +import com.jabiseo.member.domain.MemberRepository; +import com.jabiseo.member.exception.MemberBusinessException; +import com.jabiseo.member.exception.MemberErrorCode; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class DevLoginHelper { + + private final JwtHandler jwtHandler; + private final MemberRepository memberRepository; + private final RedisCacheRepository redisCacheRepository; + + public LoginResponse login(String memberId) { + Member member = memberRepository.findById(memberId) + .orElseThrow(() -> new MemberBusinessException(MemberErrorCode.MEMBER_NOT_FOUND)); + + String accessToken = jwtHandler.createAccessToken(member); + String refreshToken = jwtHandler.createRefreshToken(); + redisCacheRepository.saveToken(member.getId(), refreshToken); + return new LoginResponse(accessToken, refreshToken); + } + +} diff --git a/jabiseo-api/src/main/java/com/jabiseo/auth/controller/DevAuthController.java b/jabiseo-api/src/main/java/com/jabiseo/auth/controller/DevAuthController.java new file mode 100644 index 0000000..dd5ba53 --- /dev/null +++ b/jabiseo-api/src/main/java/com/jabiseo/auth/controller/DevAuthController.java @@ -0,0 +1,39 @@ +package com.jabiseo.auth.controller; + +import com.jabiseo.auth.application.DevLoginHelper; +import com.jabiseo.auth.dto.LoginResponse; +import com.jabiseo.exception.CommonErrorCode; +import com.jabiseo.exception.ErrorResponse; +import jakarta.validation.constraints.NotBlank; +import lombok.RequiredArgsConstructor; +import org.springframework.core.env.Environment; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api") +public class DevAuthController { + + private final Environment environment; + private final DevLoginHelper loginHelper; + private static final String LIMIT_PROFILE = "local"; + + @GetMapping("/dev/auth") + public ResponseEntity devAuth(@RequestParam(value = "member-id") @NotBlank String memberId) { + if (!isLocalProfiles(environment.getActiveProfiles())) { + return ResponseEntity.status(CommonErrorCode.FORBIDDEN.getStatusCode()).body(ErrorResponse.of(CommonErrorCode.FORBIDDEN)); + } + + LoginResponse result = loginHelper.login(memberId); + return ResponseEntity.ok(result); + } + + + private boolean isLocalProfiles(String[] profiles) { + return Arrays.asList(profiles).contains(LIMIT_PROFILE); + } + +} diff --git a/jabiseo-api/src/main/java/com/jabiseo/exception/GlobalExceptionHandler.java b/jabiseo-api/src/main/java/com/jabiseo/exception/GlobalExceptionHandler.java index 7b65240..fe7e642 100644 --- a/jabiseo-api/src/main/java/com/jabiseo/exception/GlobalExceptionHandler.java +++ b/jabiseo-api/src/main/java/com/jabiseo/exception/GlobalExceptionHandler.java @@ -2,11 +2,13 @@ import com.jabiseo.database.exception.PersistenceException; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.method.annotation.HandlerMethodValidationException; +@Slf4j @RestControllerAdvice @RequiredArgsConstructor public class GlobalExceptionHandler { @@ -28,10 +30,22 @@ public ResponseEntity handlePersistenceException(PersistenceException e) { } @ExceptionHandler(HandlerMethodValidationException.class) - public ResponseEntity handleMethodArgumentNotValidException(HandlerMethodValidationException e) { - ErrorCode code = CommonErrorCode.INVALID_REQUEST_PARAMETER; + public ResponseEntity handleMethodValidationException(HandlerMethodValidationException e) { + ErrorCode errorCode = CommonErrorCode.INVALID_REQUEST_PARAMETER; + log.error(e.getMessage()); return ResponseEntity - .status(code.getStatusCode()) - .body(new ErrorResponse(code.getMessage(), code.getErrorCode())); + .status(errorCode.getStatusCode()) + .body(new ErrorResponse(e.getMessage(), errorCode.getErrorCode())); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleException(Exception e) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(e.getMessage()); + stringBuilder.append(CommonErrorCode.INTERNAL_SERVER_ERROR.getMessage()); + return ResponseEntity + .status(ErrorCode.INTERNAL_SERVER_ERROR) + .body(new ErrorResponse(stringBuilder.toString(), CommonErrorCode.INTERNAL_SERVER_ERROR.getErrorCode())); } + } diff --git a/jabiseo-api/src/test/java/com/jabiseo/auth/controller/DevAuthControllerTest.java b/jabiseo-api/src/test/java/com/jabiseo/auth/controller/DevAuthControllerTest.java new file mode 100644 index 0000000..89bb31d --- /dev/null +++ b/jabiseo-api/src/test/java/com/jabiseo/auth/controller/DevAuthControllerTest.java @@ -0,0 +1,62 @@ +package com.jabiseo.auth.controller; + +import com.jabiseo.auth.application.DevLoginHelper; +import com.jabiseo.auth.dto.LoginResponse; +import com.jabiseo.common.security.JwtAuthenticationFilter; +import com.jabiseo.common.security.JwtExceptionFilter; +import com.jabiseo.common.security.SecurityConfig; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.env.Environment; +import org.springframework.mock.env.MockEnvironment; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@ExtendWith(SpringExtension.class) +@WebMvcTest(controllers = DevAuthController.class, excludeFilters = { + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtAuthenticationFilter.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtExceptionFilter.class) +}) +@WithMockUser +class DevAuthControllerTest { + + @Autowired + private MockMvc mockMvc; + + + @MockBean + DevLoginHelper devLoginHelper; + + @Test + @DisplayName("개발용 로그인 요청") + void devLoginSuccess() throws Exception { + //given + String memberId = "1234"; + given(devLoginHelper.login(memberId)).willReturn(new LoginResponse("accc", "refresh")); + + //when + ResultActions perform = mockMvc.perform(get("/api/dev/auth?member-id=" + memberId)); + + //then + perform.andExpect(status().isOk()) + .andExpect(jsonPath("$.accessToken").value("accc")) + .andExpect(jsonPath("$.refreshToken").value("refresh")); + } +} \ No newline at end of file diff --git a/jabiseo-common/src/main/java/com/jabiseo/exception/CommonErrorCode.java b/jabiseo-common/src/main/java/com/jabiseo/exception/CommonErrorCode.java index 73c6b87..efc3293 100644 --- a/jabiseo-common/src/main/java/com/jabiseo/exception/CommonErrorCode.java +++ b/jabiseo-common/src/main/java/com/jabiseo/exception/CommonErrorCode.java @@ -5,10 +5,10 @@ @Getter public enum CommonErrorCode implements ErrorCode { - INVALID_REQUEST_BODY("invalid request body", "COM_001", ErrorCode.BAD_REQUEST), - INTERNAL_SERVER_ERROR("server error", "COM_002", ErrorCode.INTERNAL_SERVER_ERROR), - INVALID_REQUEST_PARAMETER("invalid request parameter", "COM_003", ErrorCode.BAD_REQUEST), - ; + INVALID_REQUEST_BODY("요청 바디가 잘못됨", "COM_001", ErrorCode.BAD_REQUEST), + INTERNAL_SERVER_ERROR("서버 에러", "COM_002", ErrorCode.INTERNAL_SERVER_ERROR), + INVALID_REQUEST_PARAMETER("요청 파라미터가 잘못됨", "COM_003", ErrorCode.BAD_REQUEST), + FORBIDDEN("권한이 없거나 금지된 요청임", "COM_004", ErrorCode.FORBIDDEN); private final String message; private final String errorCode; diff --git a/jabiseo-common/src/main/java/com/jabiseo/exception/ErrorCode.java b/jabiseo-common/src/main/java/com/jabiseo/exception/ErrorCode.java index 07cdff2..23a1fb4 100644 --- a/jabiseo-common/src/main/java/com/jabiseo/exception/ErrorCode.java +++ b/jabiseo-common/src/main/java/com/jabiseo/exception/ErrorCode.java @@ -10,6 +10,8 @@ public interface ErrorCode { int INTERNAL_SERVER_ERROR = 500; + int FORBIDDEN = 403; + String getMessage(); String getErrorCode();