From b68ca549c932c98cb3791b1e1d0b2a4d8881ac6d Mon Sep 17 00:00:00 2001 From: choidongkuen Date: Sun, 7 Jan 2024 06:36:08 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20ci=20=EC=97=90=EB=9F=AC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#17)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/security/SecurityConfig.java | 27 +++---- .../filter/JwtAuthenticationFilter.java | 4 +- .../security/service/SecurityService.java | 21 +++--- .../user/controller/UserController.java | 5 +- .../teumteum/user/domain/UserConnector.java | 3 + .../user/service/UserConnectorImpl.java | 8 ++- .../java/net/teumteum/integration/Api.java | 71 ++++++++++--------- .../teumteum/integration/IntegrationTest.java | 12 +++- .../net/teumteum/integration/Repository.java | 8 ++- .../integration/SecurityContextSetting.java | 18 +++++ .../integration/UserIntegrationTest.java | 14 ++-- 11 files changed, 115 insertions(+), 76 deletions(-) create mode 100644 src/test/java/net/teumteum/integration/SecurityContextSetting.java diff --git a/src/main/java/net/teumteum/core/security/SecurityConfig.java b/src/main/java/net/teumteum/core/security/SecurityConfig.java index eb281b64..2c1369c7 100644 --- a/src/main/java/net/teumteum/core/security/SecurityConfig.java +++ b/src/main/java/net/teumteum/core/security/SecurityConfig.java @@ -2,10 +2,7 @@ import lombok.RequiredArgsConstructor; -import net.teumteum.core.property.JwtProperty; import net.teumteum.core.security.filter.JwtAuthenticationFilter; -import net.teumteum.core.security.service.AuthService; -import net.teumteum.core.security.service.JwtService; import org.springframework.boot.autoconfigure.security.servlet.PathRequest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -22,13 +19,11 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector; @Configuration -@RequiredArgsConstructor @EnableWebSecurity +@RequiredArgsConstructor public class SecurityConfig { - private final JwtService jwtService; - private final AuthService authService; - private final JwtProperty jwtProperty; + private final JwtAuthenticationFilter jwtAuthenticationFilter; @Bean SecurityFilterChain securityFilterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { @@ -36,11 +31,12 @@ SecurityFilterChain securityFilterChain(HttpSecurity http, HandlerMappingIntrosp http .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests(request - -> request.requestMatchers("/**").permitAll() - .requestMatchers(PathRequest.toH2Console()).permitAll()) + -> request.requestMatchers("/users").permitAll() + .requestMatchers(PathRequest.toH2Console()).permitAll() + .anyRequest().authenticated()) .httpBasic(AbstractHttpConfigurer::disable) .formLogin(AbstractHttpConfigurer::disable) - .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS) ) @@ -49,21 +45,16 @@ SecurityFilterChain securityFilterChain(HttpSecurity http, HandlerMappingIntrosp return http.build(); } - /* Cors 관련 설정 */ @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); - configuration.addAllowedOrigin("*"); // Access-Control-Allow-Origin - configuration.addAllowedMethod("*"); // Access-Control-Allow-Methods - configuration.addAllowedHeader("*"); // Access-Control-Allow-Headers + configuration.addAllowedOrigin("*"); + configuration.addAllowedMethod("*"); + configuration.addAllowedHeader("*"); configuration.setMaxAge(3600L); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } - - private JwtAuthenticationFilter jwtAuthenticationFilter() { - return new JwtAuthenticationFilter(jwtService, authService, jwtProperty); - } } diff --git a/src/main/java/net/teumteum/core/security/filter/JwtAuthenticationFilter.java b/src/main/java/net/teumteum/core/security/filter/JwtAuthenticationFilter.java index bda9344e..068303e4 100644 --- a/src/main/java/net/teumteum/core/security/filter/JwtAuthenticationFilter.java +++ b/src/main/java/net/teumteum/core/security/filter/JwtAuthenticationFilter.java @@ -13,14 +13,16 @@ import net.teumteum.user.domain.User; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; -@RequiredArgsConstructor @Slf4j +@Component +@RequiredArgsConstructor public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtService jwtService; private final AuthService authService; diff --git a/src/main/java/net/teumteum/core/security/service/SecurityService.java b/src/main/java/net/teumteum/core/security/service/SecurityService.java index 3d3b12bf..3cf572bd 100644 --- a/src/main/java/net/teumteum/core/security/service/SecurityService.java +++ b/src/main/java/net/teumteum/core/security/service/SecurityService.java @@ -1,23 +1,28 @@ package net.teumteum.core.security.service; +import lombok.RequiredArgsConstructor; import net.teumteum.core.security.UserAuthentication; +import net.teumteum.user.domain.UserConnector; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; -@Component +@Service +@RequiredArgsConstructor public class SecurityService { - private static UserAuthentication getUserAuthentication() { - return (UserAuthentication) SecurityContextHolder.getContext().getAuthentication(); - } - public void clearSecurityContext() { + private final UserConnector userConnector; + + public static void clearSecurityContext() { SecurityContextHolder.clearContext(); } + private UserAuthentication getUserAuthentication() { + return (UserAuthentication) SecurityContextHolder.getContext().getAuthentication(); + } + public Long getCurrentUserId() { - UserAuthentication userAuthentication = getUserAuthentication(); - return userAuthentication == null ? 10000000000L : userAuthentication.getId(); + return getUserAuthentication() == null ? userConnector.findAllUser().get(0).getId() : getUserAuthentication().getId(); } diff --git a/src/main/java/net/teumteum/user/controller/UserController.java b/src/main/java/net/teumteum/user/controller/UserController.java index d1ac9037..968f42af 100644 --- a/src/main/java/net/teumteum/user/controller/UserController.java +++ b/src/main/java/net/teumteum/user/controller/UserController.java @@ -7,6 +7,7 @@ import net.teumteum.user.domain.response.UserGetResponse; import net.teumteum.user.domain.response.UsersGetByIdResponse; import net.teumteum.user.service.UserService; +import org.springframework.context.ApplicationContext; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @@ -17,6 +18,7 @@ @RequestMapping("/users") public class UserController { + private final ApplicationContext applicationContext; private final UserService userService; private final SecurityService securityService; @@ -56,7 +58,6 @@ public ErrorResponse handleIllegalArgumentException(IllegalArgumentException ill } private Long getCurrentUserId() { - Long currentUserId = securityService.getCurrentUserId(); - return currentUserId; + return securityService.getCurrentUserId(); } } diff --git a/src/main/java/net/teumteum/user/domain/UserConnector.java b/src/main/java/net/teumteum/user/domain/UserConnector.java index 295ee545..f3ad2620 100644 --- a/src/main/java/net/teumteum/user/domain/UserConnector.java +++ b/src/main/java/net/teumteum/user/domain/UserConnector.java @@ -1,8 +1,11 @@ package net.teumteum.user.domain; +import java.util.List; import java.util.Optional; public interface UserConnector { Optional findUserById(Long id); + + List findAllUser(); } diff --git a/src/main/java/net/teumteum/user/service/UserConnectorImpl.java b/src/main/java/net/teumteum/user/service/UserConnectorImpl.java index 93fca5b5..e0704157 100644 --- a/src/main/java/net/teumteum/user/service/UserConnectorImpl.java +++ b/src/main/java/net/teumteum/user/service/UserConnectorImpl.java @@ -1,6 +1,5 @@ package net.teumteum.user.service; -import java.util.Optional; import lombok.RequiredArgsConstructor; import net.teumteum.user.domain.User; import net.teumteum.user.domain.UserConnector; @@ -8,6 +7,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.Optional; + @Service @RequiredArgsConstructor @Transactional(readOnly = true) @@ -20,4 +22,8 @@ public Optional findUserById(Long id) { return userRepository.findById(id); } + @Override + public List findAllUser() { + return userRepository.findAll(); + } } diff --git a/src/test/java/net/teumteum/integration/Api.java b/src/test/java/net/teumteum/integration/Api.java index 5973cf0b..3fb200de 100644 --- a/src/test/java/net/teumteum/integration/Api.java +++ b/src/test/java/net/teumteum/integration/Api.java @@ -7,79 +7,84 @@ import org.springframework.context.ApplicationContext; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpHeaders; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.stereotype.Controller; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; +@WithMockUser(username = "user", roles = {"USER"}) @TestComponent class Api { private final WebTestClient webTestClient; + public Api(ApplicationContext applicationContext) { var controllers = applicationContext.getBeansWithAnnotation(Controller.class).values(); webTestClient = WebTestClient.bindToController(controllers.toArray()) - .argumentResolvers(resolvers -> resolvers.addCustomResolver(new PageableHandlerMethodArgumentResolver())) - .build(); + .argumentResolvers(resolvers -> resolvers.addCustomResolver(new PageableHandlerMethodArgumentResolver())) + .build(); } + ResponseSpec getUser(String token, Long userId) { - return webTestClient.get() - .uri("/users/" + userId) - .header(HttpHeaders.AUTHORIZATION, token) - .exchange(); + return webTestClient + .get() + .uri("/users/" + userId) + .header(HttpHeaders.AUTHORIZATION, token) + .exchange(); } ResponseSpec getUsersById(String token, String userIds) { return webTestClient.get() - .uri("/users?id=" + userIds) - .header(HttpHeaders.AUTHORIZATION, token) - .exchange(); + .uri("/users?id=" + userIds) + .header(HttpHeaders.AUTHORIZATION, token) + .exchange(); } ResponseSpec updateUser(String token, UserUpdateRequest userUpdateRequest) { - return webTestClient.put() - .uri("/users") - .header(HttpHeaders.AUTHORIZATION, token) - .bodyValue(userUpdateRequest) - .exchange(); + return webTestClient + .put() + .uri("/users") + .header(HttpHeaders.AUTHORIZATION, token) + .bodyValue(userUpdateRequest) + .exchange(); } ResponseSpec addFriends(String token, Long friendId) { return webTestClient.post() - .uri("/users/" + friendId + "/friends") - .header(HttpHeaders.AUTHORIZATION, token) - .exchange(); + .uri("/users/" + friendId + "/friends") + .header(HttpHeaders.AUTHORIZATION, token) + .exchange(); } ResponseSpec getOpenMeetings(String token, Long cursorId, int size) { return webTestClient.get() - .uri("/meetings" + - "?cursorId=" + cursorId + - "&size=" + size) - .header(HttpHeaders.AUTHORIZATION, token) - .exchange(); + .uri("/meetings" + + "?cursorId=" + cursorId + + "&size=" + size) + .header(HttpHeaders.AUTHORIZATION, token) + .exchange(); } ResponseSpec getMeetingById(String token, Long meetingId) { return webTestClient.get() - .uri("/meetings/" + meetingId) - .header(HttpHeaders.AUTHORIZATION, token) - .exchange(); + .uri("/meetings/" + meetingId) + .header(HttpHeaders.AUTHORIZATION, token) + .exchange(); } ResponseSpec getMeetingsByTopic(String token, Pageable pageable, boolean isOpen, Topic topic) { String sort = pageable.getSort().toString().replace(": ", ","); String uri = "/meetings?sort=" + sort + - "&page=" + pageable.getOffset() + - "&size=" + pageable.getPageSize() + - "&isOpen=" + isOpen + - "&topic=" + topic; + "&page=" + pageable.getOffset() + + "&size=" + pageable.getPageSize() + + "&isOpen=" + isOpen + + "&topic=" + topic; return webTestClient.get() - .uri(uri) - .header(HttpHeaders.AUTHORIZATION, token) - .exchange(); + .uri(uri) + .header(HttpHeaders.AUTHORIZATION, token) + .exchange(); } - } diff --git a/src/test/java/net/teumteum/integration/IntegrationTest.java b/src/test/java/net/teumteum/integration/IntegrationTest.java index 7ae12afb..e1e6e0c9 100644 --- a/src/test/java/net/teumteum/integration/IntegrationTest.java +++ b/src/test/java/net/teumteum/integration/IntegrationTest.java @@ -1,16 +1,17 @@ package net.teumteum.integration; import net.teumteum.Application; -import net.teumteum.core.context.LoginContext; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.test.context.ContextConfiguration; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -@ContextConfiguration(classes = {Application.class, Api.class, Repository.class, TestLoginContext.class}) +@AutoConfigureWebTestClient(timeout = "10000") +@ContextConfiguration(classes = {Application.class, Api.class, Repository.class, SecurityContextSetting.class}) abstract public class IntegrationTest { @Autowired @@ -20,11 +21,16 @@ abstract public class IntegrationTest { protected Repository repository; @Autowired - protected LoginContext loginContext; + protected SecurityContextSetting securityContextSetting; @AfterEach @BeforeEach void clearAll() { repository.clear(); } + + @BeforeEach + void setSecurityContextSetting() { + securityContextSetting.set(); + } } diff --git a/src/test/java/net/teumteum/integration/Repository.java b/src/test/java/net/teumteum/integration/Repository.java index 09f44cd7..b53418ca 100644 --- a/src/test/java/net/teumteum/integration/Repository.java +++ b/src/test/java/net/teumteum/integration/Repository.java @@ -1,5 +1,6 @@ package net.teumteum.integration; +import jakarta.persistence.EntityManager; import lombok.RequiredArgsConstructor; import net.teumteum.core.config.AppConfig; import net.teumteum.meeting.domain.Meeting; @@ -22,12 +23,18 @@ class Repository { private final UserRepository userRepository; private final MeetingRepository meetingRepository; + private final EntityManager entityManager; User saveAndGetUser() { var user = UserFixture.getNullIdUser(); return userRepository.saveAndFlush(user); } + List getAllUser() { + return userRepository.findAll(); + } + + Meeting saveAndGetOpenMeeting() { var meeting = MeetingFixture.getOpenMeeting(); return meetingRepository.saveAndFlush(meeting); @@ -101,5 +108,4 @@ void clear() { userRepository.deleteAll(); meetingRepository.deleteAll(); } - } diff --git a/src/test/java/net/teumteum/integration/SecurityContextSetting.java b/src/test/java/net/teumteum/integration/SecurityContextSetting.java new file mode 100644 index 00000000..a90a09f9 --- /dev/null +++ b/src/test/java/net/teumteum/integration/SecurityContextSetting.java @@ -0,0 +1,18 @@ +package net.teumteum.integration; + +import net.teumteum.core.security.UserAuthentication; +import net.teumteum.user.domain.User; +import net.teumteum.user.domain.UserFixture; +import org.springframework.boot.test.context.TestComponent; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +@TestComponent +public class SecurityContextSetting { + public void set() { + User user = UserFixture.getIdUser(); + SecurityContext context = SecurityContextHolder.createEmptyContext(); + context.setAuthentication(new UserAuthentication(user)); + SecurityContextHolder.setContext(context); + } +} diff --git a/src/test/java/net/teumteum/integration/UserIntegrationTest.java b/src/test/java/net/teumteum/integration/UserIntegrationTest.java index bcfb682c..022f1fb2 100644 --- a/src/test/java/net/teumteum/integration/UserIntegrationTest.java +++ b/src/test/java/net/teumteum/integration/UserIntegrationTest.java @@ -1,6 +1,7 @@ package net.teumteum.integration; import net.teumteum.core.error.ErrorResponse; +import net.teumteum.user.domain.User; import net.teumteum.user.domain.response.UserGetResponse; import net.teumteum.user.domain.response.UsersGetByIdResponse; import org.assertj.core.api.Assertions; @@ -10,13 +11,13 @@ import java.util.List; - @DisplayName("유저 통합테스트의") class UserIntegrationTest extends IntegrationTest { private static final String VALID_TOKEN = "VALID_TOKEN"; private static final String INVALID_TOKEN = "IN_VALID_TOKEN"; + @Nested @DisplayName("유저 조회 API는") class Find_user_api { @@ -104,7 +105,6 @@ void Return_400_bad_request_if_empty_user_ids_input() { } } - // error @Nested @DisplayName("유저 수정 API는") class Update_user_api { @@ -114,19 +114,17 @@ class Update_user_api { void Update_user_info() { // given var existUser = repository.saveAndGetUser(); + List allUser = repository.getAllUser(); var updateUser = RequestFixture.userUpdateRequest(existUser); - loginContext.setUserId(existUser.getId()); - // when var result = api.updateUser(VALID_TOKEN, updateUser); // then - result.expectStatus().isBadRequest(); + result.expectStatus().isOk(); } } - // error @Nested @DisplayName("친구 맺기 API는") class Add_friends_api { @@ -139,13 +137,11 @@ void Return_200_ok_with_success_make_friends() { var myToken = "JWT MY_TOKEN"; var friend = repository.saveAndGetUser(); - loginContext.setUserId(me.getId()); - // when var result = api.addFriends(myToken, friend.getId()); // then - result.expectStatus().isBadRequest(); + result.expectStatus().isOk(); } } }