Java/Spring

[Spring Security] CORS 에 대하여

Icarus8050 2019. 11. 11. 03:26
반응형
  • CORS (Cross-Origin Resource Sharing)

 CORS란 웹 어플리케이션의 도메인이 다른 도메인의 리소스에 대해서 접근이 허용되는지 체크하는 매커니즘입니다. 웹 어플리케이션은 리소스를 요청하는 서버의 도메인, 프로토콜 또는 포트가 다를 경우, cross-origin HTTP request 요청을 실행합니다.

 

 보안상의 이유로, 브라우저는 cross-origin HTTP request에 대해서 same-origin policy를 적용하여 동작합니다. 즉, a.com 이라는 도메인의 클라이언트에서 리소스를 요청할 때는 a.com 이라는 도메인의 서버일 경우에 CORS 문제가 발생하지 않고 정상적으로 동작합니다. 만약 두 도메인이 서로 다르다면, CORS에 대해 Header 설정을 해주어야 cross-origin HTTP request 에 대해서 정상적으로 요청과 응답이 이루어집니다.

 


CORS 요청의 종류

 CORS 요청으로는 Simple request 와 Preflight request 가 있습니다.

 

Simple request

 Simple request 는 Preflight 체크를 하지 않으며, 클라이언트와 서버간에 한 번만 요청과 응답을 주고 받습니다. Simple request 는 아래의 조건들을 만족하면 요청하게 됩니다.

 

1. 요청 메서드

  • GET
  • HEAD
  • POST

2. 커스텀 헤더를 전송을 하지 말아야 한다.

3. 허용되는 헤더는 다음과 같다.

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type
  • Last-Event-ID
  • DPR
  • Save-Data
  • Viewport-Width
  • Width

4. Content-Type 헤더의 허용되는 Value 값은 다음과 같다.

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

 

Preflight request

 Simple request 의 조건에 만족하지 않으면 Preflight request 방식으로 요청합니다. Preflight request 는 다른 도메인에 HTTP request 를 전송하기 전에 OPTIONS 메서드로 사전 요청을 통해 서버로부터 안전한 요청인지 응답을 받고, 본 요청을 수행합니다.

 


Spring Security 에서 CORS 문제에 대해서 간단하게 해결하는 방법입니다.

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final UserDetailsServiceImpl userDetailsService;
    private final JwtProvider jwtProvider;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                
                ...
                
                .and()
                .cors()
                .and()...;
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();

        configuration.addAllowedOrigin("http://localhost:3000");
        configuration.addAllowedHeader("*");
        configuration.addAllowedMethod("*");
        configuration.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

 


 

클라이언트는 axios 를 통해서 간단하게 로그인을 위한 userId 와 password 데이터를 POST 방식으로 전송하고 있습니다. 

<script>
    import axios from 'axios'

    export default {
        name: "Login",
        data() {
            return {
                form: {
                    userId: '',
                    password: ''
                }
            }
        },
        methods: {
            tryLogin() {
                axios.post('auth/login', {
                    userId: this.form.userId,
                    password: this.form.password
                })
                    .then((res) => {
                        console.log(res.data);
                    })
                    .catch((e) => {
                        console.error(e);
                    })
            }
        }
    }
</script>

 


 

요청의 Content-Type 이 application/json 이므로, Preflight request 가 발생하여 OPTIONS 메서드로 요청을 보냅니다.

 


 

Preflight request 요청으로 200 코드를 받고나서 POST로 본 요청을 수행하여 로그인 요청을 수행합니다.

 


참고 자료

https://dev.to/effingkay/cors-preflighted-requests--options-method-3024

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

https://homoefficio.github.io/2015/07/21/Cross-Origin-Resource-Sharing/#search

https://stackoverflow.com/questions/40418441/spring-security-cors-filter

 

반응형