쌓고 쌓다

Controller 테스트시 401, 403 에러 발생 (WebMvcTest에 SecurityConfig 설정하는법) 본문

프로그래밍/spring

Controller 테스트시 401, 403 에러 발생 (WebMvcTest에 SecurityConfig 설정하는법)

승민아 2024. 1. 31. 15:23

"/members/signup" 컨트롤러 테스트 코드 실행시 401 에러를 응답으로 준다...

 

 

이 매핑은 permitAll()을 해두었는데도 말이다.

 

 

 

원인은 @WebMvcTest 어노테이션에 있었다.

 

 

 

기본적으로 @Test 어노테이션이 붙는다면 Spring Security를 auto-configure한다고 되어 있다.

 

 

@SpringBootTest와 달리 @WebMvcTest는 해당 컨트롤러 동작에 필요한 빈들만 등록하여 사용하기에 시큐리티는 제외되는것 같다.

defaultSecurityFilterChain에 보면 모든 요청에 인증이 필요한게 기본 값이다.

그래서 Spring Security는 기본 설정으로 등록되기에 해당 매핑은 인증, 인가가 필요한 것이다.

 

 

@WithMockUser를 통해 테스트시 필요한 인증 정보를 제공받을 수 있지만

 

내가 정의한 Spring Security Configuration을 불러 사용해보자.

import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
@WebMvcTest(value = {MemberController.class, TestSecurityConfig.class})
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MemberControllerTest {

    private MockMvc mockMvc;
    
    @Autowired
    private WebApplicationContext context;


    @BeforeAll
    public void setup() {
        this.mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
                .addFilter(new CharacterEncodingFilter("utf-8", true))
                .apply(springSecurity())
                .build();

    }
    
}
  •  .apply(springSecurity()) : @WebMvcTest에 스프링 시큐리티 적용을 위해 추가해준다.
  • @WebMvcTest value 속성에 내가 사용할 SecurityConfig 클래스를 함께 넣어주면 된다.

 

테스트용 SecurityConfig 클래스를 따로 만들어 적용하고 싶다면 다음과 같이한다.

테스트 폴더에 Config 클래스를 정의하고 사용한다.

 

TestSecurityConfig

package com.example.spotserver;

import com.example.spotserver.config.jwt.JwtAccessDenyHandler;
import com.example.spotserver.config.jwt.JwtAuthenticationEntryPoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class TestSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf(AbstractHttpConfigurer::disable);
        http.sessionManagement(session ->
                session
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); // 세션 생성 X

        http.authorizeHttpRequests(request ->
                request
                        .requestMatchers("/admin/**").hasAuthority("ADMIN")
                        .requestMatchers(HttpMethod.GET, "/members").authenticated()
                        .requestMatchers(HttpMethod.GET).permitAll()
                        .requestMatchers(HttpMethod.POST, "/members/signup", "/members/signin").permitAll()
                        .requestMatchers("/error").permitAll()
                        .anyRequest().authenticated());

        http.formLogin(formLogin ->
                formLogin
                        .disable()); // 폼 태그 로그인 안쓰겠다.

        http.httpBasic(httpBasic ->
                httpBasic
                        .disable()); // 기본적인 HTTP 로그인 안쓰겠다. (ID, PW를 항상 포함하여 요청함)

        http.exceptionHandling(e -> e
                .authenticationEntryPoint(new JwtAuthenticationEntryPoint())
                .accessDeniedHandler(new JwtAccessDenyHandler()));

        return http.build();
    }
}

 

 

403 에러는 csrf()를 추가해서 해결할 수 있다.

 

Comments