PROJECT-LOG/likelion.university

[디버깅] webMvcTest 수행시 401 Unauthorized 에러

HwangJerry 2023. 9. 16. 18:01

Paging 조회 API 테스트코드를 아래와 같이 작성하였고, security filterchain에서는 모든 요청에 대하여 열어두었다.

@WebMvcTest(controllers = PostController.class)
@ActiveProfiles("test")
class PostControllerTest {

    @Autowired
    private ObjectMapper om;
    @Autowired
    private MockMvc mockMvc;
    @MockBean
    private PostService postService;
    @MockBean
    private PostRepository postRepository;

    @DisplayName("유저가 입력한 키워드, 그리고 클라이언트에서 전해주는 page=0++, size=8으로 게시글을 검색/조회한다.")
    @Test
    void searchPost() throws Exception {
        // given
        String keyword = "키워드";
        String page = "0";
        String size = "8";
        MultiValueMap<String, String> info = new LinkedMultiValueMap<>();
        info.add("keyword", keyword);
        info.add("page", page);
        info.add("size", size);

        // then
        mockMvc.perform(get("http://localhost:8080/api/v1/entities")
                        .header("accept", "application/json")
                        .params(info)

                )
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(print());
    }
}

 

수행 결과는 실패였다.

 

적잖이 당황했다. 분명 filterchain에서는 permitAll()을 먹여뒀는데 401이 뜨는 것이 의아했다. 반면에 swagger에서는 또 200이 잘 떴다.

 

아무래도 내부적으로 내가 정확하게 알지 못하는 로직에 의해 필터링에 걸리는 듯 했다.

 

가정하기로는, webmvctest 로직이 일부 bean만 관리하므로 생기는 문제라고 추측하였다. 즉, webMvcTest 테스트 코드 입장에서는 securityConfig bean의 내용은 모르지만, security가 있으니 당연히 인증 프로세스를 거친다고 가정하는 것으로 보였다.

 

따라서 해당 부분을 알아본 결과, 다음과 같은 내용을 얻을 수 있었다.

  • security가 의존성으로 추가되면 기본적으로 모든 요청에 대하여 인증 절차를 거치는 것으로 기본 적용되어있기 때문에 webMvcTest 수행시에 security filter에 걸릴 수 있다.
  • 나는 코드 상에서 header에 인증 토큰을 추가해주지 않았기 때문에 401이 뜨게 된다.
  • 따라서 요청을 할 때 권한 정보를 같이 넘겨줘야 하는데, 로그인이 잘 되는지를 검증하는 test가 아니므로 이를 매번 추가해주는 것은 불필요하다. 따라서 이러한 "인증된 사용자" 또한 mock 객체로 사용할 수 있도록 @WithMockUser 라는 어노테이션을 지원해준다.
    • @WithMockUser - 인증된 사용자
    • @WithAnonymousUser - 미인증 사용자
    • @WithUserDetails - 메서드가 principal 내부의 값을 직접 사용하는 경우에 사용 (별도 사전 설정 필요)
  • security test시 403오류가 발생할 수도 있으며, 이는 csrf때문에 발생한다.
    • Test코드에서도 csrf의 주소 값을 Http 요청할때 넣어 같이 보내줘야 하므로 .with(csrf( ))을 통해 담아준다.

 

솔루션 :

@WithMockUser 추가

@DisplayName("유저가 입력한 키워드, 그리고 클라이언트에서 전해주는 page=0++, size=8으로 게시글을 검색/조회한다.")
@Test
@WithMockUser
void searchPost() throws Exception {
    // given
    String keyword = "키워드";
    String page = "0";
    String size = "8";
    MultiValueMap<String, String> info = new LinkedMultiValueMap<>();
    info.add("keyword", keyword);
    info.add("page", page);
    info.add("size", size);

    // then
    mockMvc.perform(get("http://localhost:8080/api/v1/entities")
                    .header("accept", "application/json")
//                        .params(info)
                    .param("keyword", keyword)
                    .param("page", page)
                    .param("size", size)
            )
            .andExpect(MockMvcResultMatchers.status().isOk())
            .andDo(print());
}

 

 

출처:

 

@WebMvcTest 에서 Spring Security 적용했을때 401/403 에러 발생

기존에 중복검사(예외처리)까지 한 코드에서 DB에 회원가입 정보를 저장할때 비밀번호를 암호화하기 위해 Spring Security를 사용하고 Test를 하는 과정에서 오류가 발생했다.Test 코드 실행시 401 오류

velog.io

참고(WebMvcTest 어노테이션):

 

@WebMvcTest 에서 Spring Security 적용, 401/403 에러 해결하기 - csrf

요약 401 Unauthorized -> @WithMockUser, @WithMockUserDetails 사용 403 Forbidden -> with(csrf()) 추가 @WebMvcTest Annotation that can be used for a Spring MVC test that focuses only on Spring MVC components. Using this annotation will disable full aut

sedangdang.tistory.com