CORS?

CORS λŠ”, Cross-Origin Resource Sharing, 즉 μ›Ή λΈŒλΌμš°μ €μ—μ„œ μ„œλ‘œ λ‹€λ₯Έ Origin κ°„μ˜ Resource μš”μ²­μ„ μ œμ–΄ν•˜λŠ” λΈŒλΌμš°μ € λ³΄μ•ˆ 정책이닀.

μ—¬κΈ°μ„œ Origin 은 protocol, domain(host), port 의 쑰합을 μ˜λ―Έν•œλ‹€. 예λ₯Ό λ“€μ–΄,Β http://localhost:3000 κ³ΌΒ http://localhost:8080 은 ν¬νŠΈκ°€ λ‹€λ₯΄κΈ° λ•Œλ¬Έμ— μ„œλ‘œ λ‹€λ₯Έ Origin 인 것이닀.

Why using CORS?

μ›Ή λΈŒλΌμš°μ €λŠ” SOP(Same-Origin Policy) λ₯Ό μ μš©ν•œλ‹€. 이 정책은 μ–΄λ–€ Origin μ—μ„œ ν˜ΈμΆœν•œ Script λ‚˜ λ‹€λ₯Έ Origin μ—μ„œ κ°€μ Έμ˜¨ Resource λ“±κ³Όμ˜ μƒν˜Έμž‘μš©μ„ μ œν•œν•˜λŠ” 것이닀.

λ§Œμ•½ Spring Boot μ—μ„œ Thymeleaf 둜 Front-End λ₯Ό κ΅¬ν˜„ν•œλ‹€κ³  κ°€μ •ν•˜μž. 이 μƒν™©μ—μ„œλŠ” Origin 이 λ™μΌν•˜κΈ° λ•Œλ¬Έμ— λΈŒλΌμš°μ €μ—μ„œ SOP Error κ°€ λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€.

그럼 μœ„μ™€ 같이 Front-End 와 Back-End λ₯Ό 각각 λ‹€λ₯Έ μ„œλ²„μ—μ„œ κ°œλ°œν•œλ‹€κ³  κ°€μ •ν•΄λ³΄μž. Spring Boot 와 React λ₯Ό μ‚¬μš©ν•˜μ—¬ 각각 κ°œλ°œν•œλ‹€κ³  ν–ˆμ„ λ•Œ, μ›Ή λΈŒλΌμš°μ €μ˜ μ½˜μ†” λ‘œκ·Έμ—μ„œ CORS Error λ₯Ό μ‰½κ²Œ λ§ˆμ£Όν•  수 μžˆλ‹€. μ΄λŠ” λΈŒλΌμš°μ €κ°€ Back-End API μš”μ²­μ„ λ§‰λŠ” ν˜„μƒμΈλ°, μ΄λ•Œ CORS 에 λŒ€ν•œ 섀정이 ν•„μš”ν•˜λ‹€.

How CORS works?

CORS κ°€ λ™μž‘ν•˜λŠ” 방식은 λ‹€μŒκ³Ό κ°™λ‹€.

  1. Front-End μ—μ„œ Back-End 둜 μš”μ²­μ„ 보낼 λ•Œ, λΈŒλΌμš°μ €λŠ” request header 에 Origin 정보λ₯Ό μΆ”κ°€
  2. Back-End λŠ” response 에 Access-Control-Allow-Origin header λ₯Ό μΆ”κ°€ν•˜μ—¬, μ–΄λ–€ Origin 의 request λ₯Ό ν—ˆμš©ν• μ§€ λͺ…μ‹œ
  3. λΈŒλΌμš°μ €λŠ” μžμ‹ μ˜ Origin κ³Ό, μ„œλ²„κ°€ ν—ˆμš©ν•œ Origin 을 λΉ„κ΅ν•˜μ—¬ 쑰건이 맞으면 response data λ₯Ό ν—ˆμš©, κ·Έλ ‡μ§€ μ•Šλ‹€λ©΄ CORS Error λ₯Ό λ°œμƒμ‹œν‚΄
CORS Configuration

CORS λ₯Ό Spring Boot Application 에 μ μš©μ‹œν‚€κΈ° μœ„ν•˜μ—¬λŠ” CORS 에 λŒ€ν•œ 섀정이 ν•„μš”ν•˜λ‹€.

Spring Security λ₯Ό μ‚¬μš©ν•œλ‹€λ©΄, μš°μ„  SecurityConfig class 의 SecurityFilterChain μ•ˆμ— CORS κ΄€λ ¨ 섀정을 ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€.

@Bean  
public SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {  
    http  
            .cors((cors) -> cors  
                    .configurationSource(new CorsConfigurationSource() {  
                        @Override  
                        public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {  
                            CorsConfiguration configuration = new CorsConfiguration();  
  
                            configuration.setAllowedOrigins(Collections.singletonList("http://localhost:3000"));  
                            configuration.setAllowedMethods(Collections.singletonList("*"));  
                            configuration.setAllowCredentials(true);  
                            configuration.setAllowedHeaders(Collections.singletonList("*"));  
                            configuration.setMaxAge(3600L);  
  
                            return configuration;  
                        }  
                    }))
 
    ...
}

SecurityConfig 에 λŒ€ν•œ 섀정은 보톡 둜그인 λ“±μ˜ 인가 및 인증 μž‘μ—…μ—μ„œ μˆ˜ν–‰λ˜λ―€λ‘œ λ‚˜λ¨Έμ§€ Controller 에도 CORS λ₯Ό μ„€μ •ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€. μ΄λŠ” CorsMvcConfig λ₯Ό ν†΅ν•˜μ—¬ 섀정해쀄 수 μžˆλ‹€.

@Override  
public void addCorsMappings(CorsRegistry corsRegistry) {  
    corsRegistry.addMapping("/**")  
            .allowedOrigins("http://localhost:3000");  
}