티스토리 뷰

728x90
반응형

Spring Boot 에서 MockMvc 사용 시 403 Forbidden 에러 발생

  • Spring Security를 사용하고 있으면 SpringBootWebSecurityConfiguration 자동 설정
  • 모든 Controller 요청할 때 Spring Security가 적용되어 권한이 없으면 에러 발생

MockMvc의 CSRF 비활성화

  • Spring Security는 기본적으로 CSRF(Cross-Site Request Forgery) 공격을 방지하기 위해 CSRF 토큰을 사용
  • 하지만 테스트 환경에서는 CSRF 토큰을 모의(Mock)로 주입하는 것이 번거로움
  • MockMvc 사용 시에는 CSRF 보호 기능을 비활성화하는 것이 편리
@Configuration
@EnableWebSecurity
public class TestSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable(); // CSRF 비활성화
    }
}

@WebMvcTest(HelloController.class) // HelloController 테스트를 위한 웹 계층 테스트 설정
@Import(TestSecurityConfig.class) // TestSecurityConfig 클래스를 가져와서 사용
public class HelloControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    @WithMockUser
    public void testWithCSRF() throws Exception {
        mockMvc.perform(post("/some-endpoint")
                .contentType("application/json")
                .content("{\"key\": \"value\"}"))
            .andExpect(status().isOk());
    }
}

인증되지 않은 요청을 허용하는 설정

  • 기본적으로 Spring Security는 모든 요청에 대해 인증을 요구
  • permitAll()을 사용하여 특정 URL에 대해 인증 없이 접근할 수 있도록 설정
@Configuration
@EnableWebSecurity
public class TestSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/public/**").permitAll() // 인증 없이 접근 허용
            .anyRequest().authenticated();
    }
}

Spring Security의 설정 없이 MockMvc에서 with(csrf())를 사용

  • with(csrf()) 메서드를 사용하여 CSRF 토큰을 요청에 추가
  • @WithMockUser를 통해 인증된 사용자로 간주
@AutoConfigureMockMvc
public class HelloControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    @WithMockUser // Mock 사용자를 생성하여 인증된 사용자로 요청을 보냄
    public void testWithCSRF() throws Exception {
        mockMvc.perform(post("/some-endpoint")
                .with(csrf()) // CSRF 토큰 추가
                .contentType("application/json")
                .content("{\"key\": \"value\"}"))
            .andExpect(status().isOk());
    }
}
728x90
반응형
반응형
300x250