[Spring Boot] Error: ControllerTest + Spring Security 403 에러

sy·2023년 7월 15일
0
post-custom-banner

에러 내용

java.lang.AssertionError: Status expected:<200> but was:<403>
Expected :200
Actual :403

ControllerTest

@WebMvcTest(MemberController.class)
class MemberControllerTest {

    @MockBean
    private MemberService memberService;

    @Autowired
    private MockMvc mockMvc;
    
    @Autowired
    private ObjectMapper objectMapper;

	@Test
    void duplicate() throws Exception {
        // given
        String url = "/api/duplicate/email";

        // when
        DuplicateRequestDto duplicateRequestDto = new DuplicateRequestDto(email, null);
        mockMvc.perform(MockMvcRequestBuilders.post(url)
                        .content(objectMapper.writeValueAsString(duplicateRequestDto))
                        .contentType(MediaType.APPLICATION_JSON)
                        )
                .andExpect(status().isOk());
        // then
    }
}

mockMvc.perform 요청 시 403 에러가 나오는 에러 발생

원인

Spring Security에서 제공하는 CSRF (Cross-Site Request Forgery) 보호 때문에 POST 요청에 대해 CSRF 토큰이 필요하다.

해결 방법

1. ControllerTest에 @AutoConfigureMockMvc(addFilters = false) 추가하기

@WebMvcTest(MemberController.class)
@AutoConfigureMockMvc(addFilters = false)
class MemberControllerTest {
}

이렇게 @AutoConfigureMockMvc(addFilters = false) 추가하여 Spring Security의 자동 구성을 비활성화하고 모든 요청을 허용하도록 설정할 수 있다. 하지만 이 설정은 모든 필터를 추가하지 않는 것이기 때문에 인증된 유저를 테스트할 때 무의미할 것 같아서 다른 방법을 좀 더 찾아보았다.

2. SecurityConfig에 http.csrf().disable() 추가하기 -> 해결 안됨

@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .and()
            .authorizeRequests()
            .anyRequest().permitAll()

나는 Rest API를 만들고 있고 JWT를 이용해 Access Token을 생성하였기 때문에 http.csrf().disable() 추가가 되어있었지만 403 에러가 여전히 발생하였다. 또한 permitAll()로 모든 접근을 허용하였음에도 불구하고 403 에러가 발생하였다.

3. Test 코드에 @WithMockUser, with(csrf()) 추가하기

@Test
@WithMockUser
void duplicate() throws Exception {
    // given
    String url = "/api/duplicate/email";

    // when
    DuplicateRequestDto duplicateRequestDto = new DuplicateRequestDto(email, null);
    mockMvc.perform(MockMvcRequestBuilders.post(url)
                    .content(objectMapper.writeValueAsString(duplicateRequestDto))
                    .contentType(MediaType.APPLICATION_JSON)
                    .with(csrf()))
            .andExpect(status().isOk());
}

인증된 유저를 추가하고 csrf 토큰을 코드에 추가해주어 status 200 이 나오도록 해결하였다.

post-custom-banner

0개의 댓글