[Junit] WebMvcTest 401, 403 에러

General Dong·2024년 9월 14일

401 에러 발생 원인

프로젝트에서 Spring SecurityJWT를 적용 중이다.
MockMvc로 API 테스트 시, 사용자 인증이 안되어 401 에러가 발생하였다.

401 에러 해결

/* Mock 사용자를 만드는 어노테이션 */
@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)
public @interface WithMockCustomUser {

    String userName() default "1";
    String roleType() default "RULE_USER";
}
/* JWT Filter와 비슷한 로직의 Mock Filter */
public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory<WithMockCustomUser> {
    @Override
    public SecurityContext createSecurityContext(WithMockCustomUser annotation) {
        final SecurityContext securityContext = SecurityContextHolder.createEmptyContext();

        final Collection<GrantedAuthority> authorities = List.of(new SimpleGrantedAuthority(annotation.roleType()));

        final Authentication authentication = new UsernamePasswordAuthenticationToken(annotation.userName(), "", authorities);

        securityContext.setAuthentication(authentication);

        return securityContext;
    }
}

가짜 유저의 Authentication 객체를 새로 만든 Security Context에 저장되도록 했다.
가짜 인증을 통해 DB를 사용하지 않아도 됨으로 간편하게 테스트 가능하다.

위 코드처럼 단위 테스트에 @WithMockCustomUser 어노테이션을 추가하면 401 에러를 우회할 수 있다.


403 에러 발생 원인

401 에러가 해결된 후에 403 에러가 발생하였다.
401로 사용자가 인증은 되었지만 해당 API에 대한 권한이 없기 때문에 발생한 것이다.

이는 Spring Security가 기본적으로 CSRF 공격으로부터 방어하도록 설정되어 있기 때문이다.
그래서 CSRF Token이 없으면 권한이 없다고 판단하게 되는 것이다.

403 에러 해결

ResultActions result = mockMvc.perform(
		post("/api/login/naver")
			.with(csrf())   // CSRF Token 추가
			.content(objectMapper.writeValueAsString(request))
			.contentType(MediaType.APPLICATION_JSON)
);

테스트 요청을 보내는 코드에 .with(csrf())를 추가하여 CSRF Token이 포함되어 요청하도록 테스트 한다.


참고

401 에러 해결
403 에러 해결

profile
개발에 대한 기록과 복습을 위한 블로그 | Back-end Developer

0개의 댓글