diff --git a/backend/src/main/java/io/f1/backend/domain/user/api/TestUserController.java b/backend/src/main/java/io/f1/backend/domain/user/api/TestUserController.java new file mode 100644 index 00000000..b09feacc --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/user/api/TestUserController.java @@ -0,0 +1,29 @@ +package io.f1.backend.domain.user.api; + +import io.f1.backend.domain.user.app.TestUserService; + +import jakarta.servlet.http.HttpSession; + +import lombok.RequiredArgsConstructor; + +import org.springframework.context.annotation.Profile; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Profile("!prod") +@RequiredArgsConstructor +@RequestMapping("/user/test") +public class TestUserController { + + private final TestUserService userService; + + @PostMapping("/login/{userId}") + public ResponseEntity login(@PathVariable Long userId, HttpSession session) { + userService.login(userId, session); + return ResponseEntity.ok().build(); + } +} diff --git a/backend/src/main/java/io/f1/backend/domain/user/app/TestUserService.java b/backend/src/main/java/io/f1/backend/domain/user/app/TestUserService.java new file mode 100644 index 00000000..b3253764 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/user/app/TestUserService.java @@ -0,0 +1,38 @@ +package io.f1.backend.domain.user.app; + + +import io.f1.backend.domain.user.dao.UserRepository; +import io.f1.backend.domain.user.entity.User; +import io.f1.backend.global.exception.CustomException; +import io.f1.backend.global.exception.errorcode.UserErrorCode; +import io.f1.backend.global.security.util.SecurityUtils; + +import jakarta.servlet.http.HttpSession; + +import lombok.RequiredArgsConstructor; + +import org.springframework.context.annotation.Profile; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Profile("!prod") +@RequiredArgsConstructor +public class TestUserService { + + private final UserRepository userRepository; + + @Transactional(readOnly = true) + public void login(Long userId, HttpSession session) { + User user = + userRepository + .findById(userId) + .orElseThrow(() -> new CustomException(UserErrorCode.USER_NOT_FOUND)); + + SecurityUtils.setAuthentication(user); + SecurityContext context = SecurityContextHolder.getContext(); + session.setAttribute("SPRING_SECURITY_CONTEXT", context); + } +} diff --git a/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java b/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java index cb176ceb..79a8c2a3 100644 --- a/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java +++ b/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java @@ -51,6 +51,7 @@ public SecurityFilterChain userFilterChain(HttpSecurity http) throws Exception { "/css/**", "/js/**", "/admin/login", + "/user/test/**", actuatorBasePath + "/**") .permitAll() .requestMatchers(HttpMethod.OPTIONS, "/**") diff --git a/backend/src/test/java/io/f1/backend/domain/user/TestUserBrowserTest.java b/backend/src/test/java/io/f1/backend/domain/user/TestUserBrowserTest.java new file mode 100644 index 00000000..7c925745 --- /dev/null +++ b/backend/src/test/java/io/f1/backend/domain/user/TestUserBrowserTest.java @@ -0,0 +1,60 @@ +package io.f1.backend.domain.user; + + +import static org.assertj.core.api.Assertions.assertThat; +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.MockMvcResultMatchers.status; + +import com.github.database.rider.core.api.dataset.DataSet; + +import io.f1.backend.domain.user.dto.UserPrincipal; +import io.f1.backend.global.template.BrowserTestTemplate; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.test.web.servlet.ResultActions; + +public class TestUserBrowserTest extends BrowserTestTemplate { + + @Test + @DataSet("datasets/user.yml") + @DisplayName("테스트 유저가 로그인하면 세션에 SecurityContext가 저장된다") + void testUserLogin() throws Exception { + // given + MockHttpSession session = new MockHttpSession(); + + // when + ResultActions result = mockMvc.perform(post("/user/test/login/1").session(session)); + + // then + result.andExpect(status().isOk()); + assertThat(session.getAttribute("SPRING_SECURITY_CONTEXT")).isNotNull(); + + SecurityContext context = (SecurityContext) session.getAttribute("SPRING_SECURITY_CONTEXT"); + assertThat(context.getAuthentication().getPrincipal()).isInstanceOf(UserPrincipal.class); + + UserPrincipal userPrincipal = (UserPrincipal) context.getAuthentication().getPrincipal(); + assertThat(userPrincipal.getUserId()).isEqualTo(1L); + assertThat(userPrincipal.getUserNickname()).isEqualTo("USER1"); + } + + @Test + @DataSet("datasets/stat/one-user-stat.yml") + @DisplayName("테스트 유저가 로그인하면 마이페이지에 접근이 가능하다") + void testUserLoginSecurityContext() throws Exception { + // given + MockHttpSession session = new MockHttpSession(); + + // when + ResultActions beforeLogin = mockMvc.perform(get("/user/me").session(session)); + mockMvc.perform(post("/user/test/login/1").session(session)); + ResultActions afterLogin = mockMvc.perform(get("/user/me").session(session)); + + // then + beforeLogin.andExpect(status().isUnauthorized()); + afterLogin.andExpect(status().isOk()); + } +}