BE/Spring-Boot

[SpringBoot] Spring Security + React CORS 문제 해결

suhyeon chae 2023. 7. 8. 23:23
 --- 기존 설정들
}
,
"proxy": "http://localhost:8080",
  "devDependencies": {
    "@types/js-cookie": "^3.0.3",
    "@types/styled-components": "^5.1.26"
  }

기존에 spring에서 설정해서 잘 됐던 문제가 spring security를 적용하니 react와 spring간 cors 문제가 발생하여 통신이 안되는 오류가 있었다.

기존 설정
기존 React와 통신하기 위한 설정 코드
@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
    private final long MAX_AGE_SECS = 3600;

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 모든 경로에 대해
        registry.addMapping("/**")
                // Origin이 localhost:3000에 대해
                .allowedOrigins(
                        "http://localhost:3000"
                )
                // GET, POST, PUT, PATCH, DELETE, OPTIONS 메서드를 허용한다.
                .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(MAX_AGE_SECS);
    }

}

 

해결 방안
1. react package.jsonproxy 설정
 // 기존 설정들
},
"proxy": "http://localhost:8080",
  "devDependencies": {
    "@types/js-cookie": "^3.0.3",
    "@types/styled-components": "^5.1.26"
  }
2. security config 파일에 아래 코드 추가
// 인증이 필요한 페이지 
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
// 전체 코드
@Configuration
@RequiredArgsConstructor
public class SecurityConfig {

    private final JwtTokenProvider jwtTokenProvider;

    @Qualifier("customAuthenticationEntryPoint")
    private final AuthenticationEntryPoint authEntryPoint;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // JWT를 사용하기 위해서는 기본적으로 password encoder가 필요한데, 여기서는 Bycrypt encoder를 사용했다.
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .httpBasic().disable()
                .csrf().disable() // rest api이므로 basic auth 및 csrf 보안을 사용하지 않는다는 설정이다.
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // JWT를 사용하기 때문에 세션을 사용하지 않는다는 설정이다.
                .and()
                .authorizeHttpRequests(requests -> requests
                        // 인증이 필요한 페이지 (이 부분 추가)
                        .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                        .requestMatchers("/design/**").authenticated()
                        .anyRequest().permitAll())
                .exceptionHandling()
                .authenticationEntryPoint(authEntryPoint)
                .and()
                .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class); // JWT 인증을 위하여 직접 구현한 필터를 UsernamePasswordAuthenticationFilter 전에 실행하겠다는 설정이다
        return http.build();
    }
}