본문 바로가기
Spring

[Springboot]@WebMvcTest 사용 중 security csrf 오류 해결

by seeker00 2023. 11. 26.

0. @WebMvcTest 란?

  • @WebMvcTest 는 웹(컨트롤러) 레이어에서의 테스트를 수행할 수 있도록 돕는 어노테이션입니다.
  • presentation, web 레이어 관련 빈들만 로드(등록)하여 테스트를 수행하므로 @SpringBootTest에 비해 속도가 한결 빠릅니다.

1. 빈 생성 오류 발생시 해결 방안

  • 그러나 이런 특성으로 인해서 security를 활용하는 경우, 특정 빈들이 로드되지 않아 빈 생성 오류가 발생하기도 합니다.
    • 저의 경우에는 토큰 파싱을 수행하는 필터 클래스와 관련된 빈들이 말썽이었고, 웹 레이어 테스트 수행에서 해당 필터의 기능이 테스트 되는 것은 아니었으므로 이를 제외하는 방향으로 테스트 코드에서 어노테이션을 아래와 같이 등록하였습니다.
@WebMvcTest(controllers = ActivityRecordController.class,
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtAuthenticationFilter.class)})

 

2. csrf 오류 발생시 해결 방안

  • 그리고 이 외의 security 와 연관된 다른 빈들의 경우에도 디폴트 빈들이 등록되면서 여러 세팅들이 기본 상태로 변경되었을 것입니다.
  • 그렇기에 웹 레이어 테스트를 진행하면, csrf 인증과 관해서 403 오류가 발생하게 됩니다.
  • 이를 해소하기 위한 몇가지 방안이 있는데 가장 쉬운 접근법은 테스트 코드에 csrf() 메소드를 추가함으로써, 관련 토큰을 시큐리티 필터에 전달해 인증 과정을 통과하는 것입니다.
  mockMvc.perform(delete("/api/v1/test/3").with(csrf()))
              .andExpect(status().isOk())
              .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
              .andDo(print());
  • 만약 이 웹 레이어 테스트 코드를 이용해서 rest docs 문서를 작성하고자 한다면, rest docs 에서도 이 csrf 토큰이 요청에서 활용되는 것을 확인하실 수 있을 겁니다.
    • rest docs가 야무지게 이 csrf 토큰까지 인식해서 문서를 만들어줄 것이기 때문입니다. 아래와 같이 _csrf 토큰이 들어간 게 확인이 될 거에요.
    • 아쉽지만 저는 세션 사용을 하지 않고, csrf 보호를 위한 토큰도 사용할 예정이 없으므로 다른 방법을 사용해야 합니다.

 

Spring WebMvcTest with post returns 403

I'm wondering where the issue is with my code, every time I run a post test (irrespective of what controller it targets, or method), I return a 403 error, when in some cases I expect a 401, and in ...

stackoverflow.com

  • 위 답변을 보면 앞서 말씀드린 csrf() 메소드 이용 방법 외에 2가지 방안이 더 제시되어 있습니다.
  • 저는 그 중 한가지를 참고해서 아래와 같이 @TestConfiguration 클래스를 하나 생성해서 csrf 프로텍션을 비활성화 해주었습니다.
    • 그리고 이 config 용 클래스를 저의 테스트 코드 클래스에서 로드할 수 있도록 임포트 어노테이션을 추가( @Import(WebMvcConfigWithoutCsrf.class) )해주었습니다.
@TestConfiguration
public class WebMvcConfigWithoutCsrf extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        super.configure(http);
        http.csrf().disable();
    }
}
  • 이로써 저의 의도대로 웹 레이어 테스트 코드는 다른 문제 없이 잘 동작하며, rest-docs 또한 저의 의도대로 작성되었습니다.