반응형
프로젝트에 처음으로 테스트 코드를 도입하면서 @WithMockUser 를 사용한 테스트에서 예상치 못한 문제를 경험했다.
@WithMockUser 로 인증된 사용자로 요청을 목킹하고 있었는데, GET 요청에서는 문제없이 잘 작동하지만 POST 요청에서는 403 Forbidden 이 발생하는 것이다.
@Test
@WithMockUser(roles = "SELLER")
@DisplayName("이름 없이 스토어 생성을 요청하면, 400 에러를 반환한다.")
void test1() throws Exception {
// Given
CreateStoreRequest request = CreateStoreRequest.builder()
.description("Test description")
.build();
// Expected
mockMvc.perform(MockMvcRequestBuilders.post("/api/store")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request))
)
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.message").value("스토어 이름은 필수 입니다."))
.andDo(print());
}
원인 분석
Spring Security 의 CSRF 보호 기능이 문제였다.
Spring Security 는 기본적으로 CSRF 공격을 방지하기 위해 POST, PUT, DELETE 등 요청에는 CSRF 토큰이 필요하다.
사용자를 목킹할때, CSRF 토큰이 포함되지 않았기 때문에 403 Forbidden 오류가 발생하였다.
Spring Security 설정에 csrf() 를 disable 시켰지만, 테스트 코드에서는 가볍게 진행하기 위해 SecurityConfig.class를 빈으로 등록하지 않아, 해당 설정이 적용되지 않았다.
해결 방법
mockMvc.perform(MockMvcRequestBuilders.post("/api/store")
.with(csrf()) // CSRF 토큰 포함
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request))
)
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.message").value("스토어 이름은 필수 입니다."))
.andDo(print());
'with(csrf())' 메서드를 사용하여 요청에 csrf 토큰을 포함시켰다.
SecurityConfig.class 를 빈으로 등록시킬까? 고민했지만 그럼 의존관계에 있는 다른 클래스도 빈으로 등록하여야 해서 요청에 csrf 토큰을 추가하기로 했다.
반응형