본 문제는 Springboot 2.7(Spring 5.7) 이상 버전으로 Spring Security를 적용한 @WebMvcTest
를 할 때 발생할 수 있는 이슈를 담고 있습니다.
필자 역시 이와 동일한 문제를 `또` 겪었기에 기왕 이렇게된 김에 블로그로 포스트하여 더 이상 시간 낭비를 하지 않기 위해 기록하고자 한다.
@WebMvcTest
를 사용하여 슬라이스 테스트를 하는 도중 예상치 못하게 에러가 많이 보이고, Forbidden과 Unauthorized 에러를 봤다. 분명히 Springboot 2.7+ 이상에서 WebSecurityConfigurerAdapter
가 deprecated
되면서 직접 빈으로 등록하라고 했기에 SecurityFilterChain
으로 등록을 해주었는 데, 등록되지 않았다.
문제가 발생한 이유를 찾는 것은 그리 어렵지 않았다.
@WebMvcTest
가 테스트 컨텍스트에 어떤 빈들을 등록하는 지를 알면 이유를 쉽게 알 수 있었다.
다음은 자동으로 컨텍스트에 등록하는 빈들이다.
@Controller
@ControllerAdvice
@JsonComponent
Converter
GenericConverter
Filter
WebMvcConfigure
WebSecurityConfigurerAdapter
HandlerMethodArgumentResolver
그 어디에도 @EnableWebSecurity
혹은 SecurityFilterChain
는 등록되지 않는다.
(@EnableWebSecurity
을 언급하는 이유는 그 안에 GlobalSecurity
어노테이션이 포함되어 있기에 언급했다.)
그렇기에 스프링 개발(지원)팀에서 언급한 새로운 방법으로는 지원해주지 않고 있기 때문에 이러한 문제가 발생하고 있는 것이다.
사실 스프링 개발(지원)팀에서도 이미 이러한 문제를 파악하고 있다. (이 글을 작성하고 있는 시점에서는) 스프링 공식 깃허브 이슈를 자주 찾아보는 개발자분들이라면 알고 계시지만, 이미 이러한 문제를 파악하고 이슈로 올라가있다. (물론 Closed 되어 있다.)
(이슈가 궁금하다면 링크를 참고 바란다.)
이슈에서 언급된 말을 빌리자면, 굳이 @WebMvcTest
에서 Security까지 신경쓸 필요는 없다고 한다. (정확히는 사용자 어플리케이션이 아닌 Spring Security에서 제공되고 있는 것이기 제공하지 않는 다고 한다.) 또한, 일부 사용자들이 원치않을 경우도 고려해야하는 입장이기에 원할 경우 직접 설정하라고 한다.
추가적으로 필자가 생각했을 때에도 사용자가 임의로 정의(수정)한 SecurityFilterChain
빈 선언을 100% 신뢰하기 어려울 수 있기 때문이라는 생각도 들었다.
(사용자는 항상 고양이 같이 뭘 어떻게 건드릴지 모르는 일이니 말이다.)
해결방법은 이슈 링크에도 언급되어 있듯이 @ImportAutoConfiguration
혹은 @Import
를 사용하여 필요한 클래스를 등록하라고 한다.
공식적으로는 해결 방법 중 하나이다. 그 외에도 방법은 여러가지이니, 무엇을 테스트할지에 따라 달라진다.
필자는 2가지 방법으로 문제를 해결했다.
한 가지는 공식적인 방법을 사용했고, 다른 한 가지는 FIRST따윈 개나 줘버린 방법이다.
@TestConfiguration
으로 직접 SecurityFilterChain
을 빈으로 등록하는 클래스를 정의하고선, 이를 테스트 클래스에서 @Import하여 사용했다.
그리고 권한이 필요한 부분은 @WithAnonymousUser
, @WithMockUser
, @WithUserDetails
, @WithSecurityContext
어노테이션을 사용했다.
단순히 @SpringBootTest
를 사용하는 방법이다. 모든 빈들을 등록하는 단순하고 무식한 방법이지만, 문제는 해결된다. 대신 FIRST는 개나 줘버리기 때문에 문제가 발생하거나 속도가 느릴 수 있다는 사실은 잊어선 안된다.
스프링에서 왜 지원해주지 않는 지 어느 정도 알게 되었다. 추가적으로 의외로 이와 관련된 포스트가 많이 없는 것처럼 보이는 것은 필자의 기분 탓이었음 한다.
(이미 필자처럼 찾아서 공식 방법으로 사용하고 있기를 희망한다.. @SpringBootTest
는 정말 사용하지 않았으면 한다. (의존성이 박살난 것이 아니라면 말이다.))
여담이지만, 1년 전까지만 해도 이 문제를 해결하지 못해서 그냥 단순 무식하게 @SpringBootTest
를 사용해서 문제를 해결했다.