이 포스트를 통해
- Spring MVC에서의 CORS 설정
- Spring Security를 사용했을 때의 CORS 설정
을 적어보려 한다.
만약 cors 자체에 대해 이해가 부족한 상황이라면 아래 포스트 글을 참조하면 좋을 거 같다.
정리가 매우 잘 되어 있어 첨부했다.
Spring MVC와 Spring Security를 구분한 이유
Spring에서 CORS 이슈가 발생할 수 있는 곳은 MVC단과 Security단이 있다.
이렇게 구분하는 이유는 각 요청이 처리하는 곳이 다르기 때문이다.
인증, 인가가 필요한 요청을 Security단이 요청을 받아 응답을 반환하고,
인증, 인가가 필요없는 요청에 대해서는 Security단을 지나치고 MVC단에서 요청을 받아 응답을 한다.
이 상황에서 CORS 에러가 터지는 이유는 Preflight 요청 떄문이다.
브라우저는 실제 요청을 보내기 전에 Preflight 요청을 먼저 보내게 된다.
요청을 받은 서버는 이 요청 url을 확인해 Security단 혹은 MVC단에서 처리한다.
여기서 MVC단에 대한 CORS 설정만 해주고, Security단 cors를 설정 안해주면 에러가 터질 수 있다.
Prefilight요청은 Security에서 처리하는 데, CORS는 MVC단에만 설정되어 있어 응답에 CORS 설정이 되지 않기 때문이다.
과정에 따라 상황을 정리해보자면
- 브라우저는 실제 요청을 보내기 전에 Prefilight 요청을 보내 서버를 통해 이 요청을 보내도 되는 지 판단한다.(login id, pw등의 민감정보를 보내기 전에 검사하는 거라 생각하면 된다.)
- Preflight 요청을 받은 서버는 이에 대한 응답을 한다.
- Security를 거쳐야하는 요청이면 Security단이 응답을 한다.
- Security를 거치지 않는 요청이면 MVC단이 응답을 한다.
- 응답 헤더에는 Access-Control-Allow-Origin 필드에는 허용하는 url이 포함되어 있다.
- 브라우저는 이 Access-Control-Allow-Origin 필드를 보고 자신의 웹페이지의 출처가 포함되어 있는 지 확인한다.
- 포함되어 있으면 실제 요청을 해 응답을 받아온다.(물론 이 응답에도 Access-Control-Allow-Origin가 포함되어 있다.)
- 포함되어 있지 않다면 CORS 에러를 반환한다.
1. Spring MVC에서의 CORS설정
만약 Spring Security를 사용하지 않는다면 이 CORS 설정만으로도 충분하다.
Spring MVC에서 CORS를 설정하는 방법은 두 가지가 있다.
- 각 Controller Method에 설정
- 전역으로 설정
각 Controller Method에 설정하는 방법
@CrossOrigin
애노테이션을 활용하는 방법이다.
@CrossOrigin
애노테이션을 사용하여 특정 컨트롤러나 메서드에 대해 CORS 정책을 설정할 수 있다.
컨트롤러에 설정
@RestController
@CrossOrigin(origins = "http://localhost:3000") //이 출처에서 오는 요청 허용
@RequestMapping("/api")
public class MyController {
@GetMapping("/data")
public ResponseEntity<String> getData() {
return ResponseEntity.ok("This is data");
}
}
특정 메서드에만 설정
@RequestMapping("/api")
public class MyController {
@GetMapping("/data")
@CrossOrigin(origins = "http://localhost:3000") //getData에만 cors 설정
public ResponseEntity<String> getData() {
return ResponseEntity.ok("This is data");
}
@PostMapping("/submit")
public ResponseEntity<String> submitData() {
return ResponseEntity.ok("Data submitted");
}
}
전역으로 설정하는 방법
- WebConfig라는 클래스를 만든다.
- 아래와 같이 작성한다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCors(final CorsRegistry registry) {
registry
.addMapping("/**")
.allowedHeaders("*")
.allowedOrigins("http://localhost:3000");
.allowedMethods("*");
}
}
이 설정은 MVC단에 대한 CORS를 설정해주는 설정 클래스이다.
이 설정파일을 읽어 자동으로 응답에 CORS 관련 헤더들을 추가해준다.
1. registry.addMapping("/")
- 역할: 모든 경로(
/**
)에 대해 CORS 정책을 적용한다. - 의미: 이 설정은 애플리케이션의 모든 엔드포인트에 대해 CORS 요청을 허용한다는 의미이다.
2. allowedHeaders("*")
- 역할: 모든 요청 헤더를 허용한다.
- 의미: 클라이언트가 어떤 헤더를 요청에 포함하든, 서버는 이를 허용하겠다는 의미입니다. 예를 들어,
Content-Type
,Authorization
등의 모든 헤더가 허용된다. allowedHeaders("SET-COOKIE", "Authorization")
등으로 특정 헤더만 허용할 수 있다.
3. allowedOrigins("http://localhost:3000")
- 역할:
http://localhost:3000
에서 오는 요청만을 허용한다. - 의미: 이 설정은
http://localhost:3000
출처에서 오는 요청만이 CORS 정책에 따라 허용된다는 것을 의미한다. - 이 부분에 프론트의 url(http, 도메인, 포트)을 명시한다.
4. allowedMethods("*")
- 역할: 모든 HTTP 메서드를 허용한다.
- 의미: 이 설정은
GET
,POST
,PUT
,DELETE
,OPTIONS
,PATCH
등 모든 HTTP 메서드에 대한 요청을 허용한다는 것을 의미한다. allowedMethods("GET", "POST")
등으로 특정 Method만 허용할 수 있다.
Spring Security를 사용했을 때의 CORS 설정하는 방법
시큐리티 단에서 CORS 설정은 MVC단과 다르다.
시큐리티단을 거치는 모든 api에 대해서는 시큐리티 단에서 CORS 설정을 해줄 수 있다.
(Security설정을 하면 모든 요청에 대해 우선적으로 시큐리티단에서 요청을 받기에 별도로 MVC단에 대한 CORS 설정을 해줄 필요가 없다.)
설정하는 방법은 다음과 같다.
- Cors관련 파일(CorsConfig)을 생성한다.
- SecurityConfig에 적용해준다.
CorsConfig
@Configuration
public class CorsConfig {
@Bean
public UrlBasedCorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
// Using set methods instead of add methods
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
1. corsConfigurationSource
메서드
- 메서드 역할: 이 메서드는 CORS 정책을 설정하는
UrlBasedCorsConfigurationSource
객체를 생성하고 반환한다. 이 객체는 URL 경로에 따라 CORS 정책을 등록하고 관리하는 역할을 한다.
2. CorsConfiguration
객체
- 역할: CORS 정책을 정의하는 객체이다. 이 객체에서 CORS 정책의 세부 사항을 설정한다.
setAllowedOrigins(Arrays.asList("http://localhost:3000"))
:http://localhost:3000
출처(origin)에서 오는 요청만 허용하도록 설정한다.- CORS 정책에서 허용할 출처를 설정하는 부분이다.
setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"))
:- 허용할 HTTP 메서드를 설정이다. 여기서는
GET
,POST
,PUT
,DELETE
,OPTIONS
메서드를 허용하도록 설정이다.
- 허용할 HTTP 메서드를 설정이다. 여기서는
setAllowedHeaders(Arrays.asList("*"))
:- 모든 헤더를 허용한다. 클라이언트가 어떤 헤더를 사용해 요청하든지 서버에서 이를 허용하도록 설정한다.
setAllowCredentials(true)
:- 자격 증명(예: 쿠키, 인증 헤더 등)을 포함한 요청을 허용하도록 설정한다. 이 설정을
true
로 하면 클라이언트에서 자격 증명을 포함해 서버에 요청을 보낼 수 있다.
- 자격 증명(예: 쿠키, 인증 헤더 등)을 포함한 요청을 허용하도록 설정한다. 이 설정을
3. UrlBasedCorsConfigurationSource
객체
- 역할: URL 패턴에 따라 CORS 정책을 등록하고 관리하는 역할을 한다.
- `source.registerCorsConfiguration("/", configuration)`**:
- 모든 경로(
/**
)에 대해 위에서 설정한 CORS 정책(configuration
)을 적용한다. - 즉, 애플리케이션의 모든 엔드포인트에 대해 위에서 설정한 CORS 정책이 적용한다.`
- 모든 경로(
SecurityConfig 설정
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UrlBasedCorsConfigurationSource ConfigurationSource;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors(cors -> cors.configurationSource(ConfigurationSource)) // 이 부분
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated();
}
}
참고: SecurityConfig(시큐리티 설정파일)에서 .cors(AbstractHttpConfigurer::disable)
은 무슨 설정이었을까?
이 설정을 말 그대로 Security단에서 Cors 설정을 하지 않는다는 것이다.
즉 cors 인증을 해야하는 요청에 대해서도 Security단에서 처리해주지 않는다는 의미이다.
즉 동일 출처에 대해서만 허용한다 생각하면 될 거 같다.
결론
Security를 사용하는 상황과 안 사용하는 상황을 잘 구분하여 설정를 해주자.
'Spring > Spring Security' 카테고리의 다른 글
Spring Security(스프링 시큐리티)의 동작 원리(Filter, FilterChain, Filter의 구조등) (1) | 2024.06.21 |
---|