이노베이션 캠프 WIL

5주차 WIL(CORS)

mat_hoyoung 2022. 7. 24.

오늘 배울 것은 CORS다  먼저 Cors가 무엇일까 >?

한줄 요약을 해주자면!  cors == 브라우저 보안정책 이라고 보면된다 

 

 

끝!!! .... 이 아니라 자세히 알아보자.  

 

먼저 콘솔 에러창에 수많은 에러가 뜰수 있다 그중에서 Access...Control-Allow-Origin...with CORS disabled.  이런 에러가 뜬다면 cors 설정을 해줘야 한다. 설정을 변경하기전에 

 

왜 이런 에러가 뜰까 ?? 

CORS 에러는 브라우저에서 서로 다른 도메인/포트의 서버로 요청이 갈때 브라우저에서 발생한다. 

 

.해결 방법으로 

  • 미들웨어 설치 & 설정 (프론트엔드/백엔드 둘다 해당)
  • 프록시방식 사용 : 브라우저에서 프론트서버로 요청 > 프론트서버에서 백엔드서버로 요청.
    프론트에서 요청 header에 Access-Control-Allow-Origin:'도메인:포트 or *(모든도메인)' 옵션 사용이 있다. 

 

총 정리해서 다시 설명해 주자면 

프론트의 도메인이 localhost: 8000이며 백엔드의 도메인은  localhost: 9000일 경우에 

1. 프론트 엔드에서는 백엔드로 api 를 보냄

 

2. 백엔드에서는 프론트와 백엔드의 도메인이 달라진 것을 감지함. 

 

3. cors가 허용하는 여부에 따라서 프론트엔드가 요청한 것을 허용 또는 거부함 

 

스프링 부트로 cors를 해결하는 방법은 무엇일까 ? 

 

이런 Preflight 상황에서 적절한 Access-Control 을 위한 해결 방법이 3가지가 존재한다.

 

  1. CorsFilter 로 직접 response에 header 를 넣어주기
  2. Controller 에서 @CrossOrigin 어노테이션 추가하기
  3. WebMvcConfigurer 를 이용해서 처리하기

CorsFilter 생성하기

 

첫 번째로 알아볼 방법은 커스텀 필터를 만드는 것이다.


Access-Control 을 확인할 수 있도록 커스텀 Filter 를 생성해보자.

 

 

필자는 이러한 구조인데, 아무 위치에서도 좋으니 filter 라는 디렉토리를 생성한다.

 

그리고 해당 디렉토리 아래에 CorsFilter 라는 클래스를 하나 생성해보도록 하자.

 

 

그리고 해당 클래스를 Bean 으로 등록하기 위해서 프레임워크에게 알려야 한다.


@Component 이라는 어노테이션을 추가하고, Filter 인터페이스를 구현하여 Override 해보자.

 

주의해야할 것이 있는데, Filter 는 꼭 javax.servlet 의 Filter를 사용해야 한다.

 

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

    }

    @Override
    public void destroy() {

    }
}

 

우리는 해당 필터가 실제로 수행할 doFilter 를 커스텀해야 한다.

 

다음과 같이 작성해보자.

 

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods","*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept, Authorization");

        if("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        }else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void destroy() {

    }
}

 

우리가 필요한 헤더를 OPTIONS 가 잘 확인할 수 있도록 설정해줄 수 있다.

 

CrossOrigin 어노테이션 사용하기

 

CrossOrigin 어노테이션을 사용하는 방법은 매우 간단하다.

 

컨트롤러에서 특정 메서드 혹은 컨트롤러 상단부에 @CrossOrigin 만 추가하면 된다.

 

@RestController
@RequestMapping(value = "/api/threats", produces = "application/json")
@CrossOrigin(origins = "http://front-server.com") // 컨트롤러에서 설정
public class ThreatController {

    private final ThreatService threatService;

    public ThreatController(ThreatService threatService) {
        this.threatService = threatService;
    }

    @GetMapping
    @CrossOrigin(origins = "http://front-server.com") // 메서드에서 설정
    public ResponseEntity<ThreatLogCountResponse> getAllThreatLogs() {
        return ResponseEntity.ok(threatService.getAllThreatLogCount());
    }
}

 

설정 방법은 2가지가 있는데,

 

  1. 컨트롤러 클래스 단에서 설정
  2. 메서드 단에서 설정

 

둘중 하나의 방법만 사용해도 된다.

 

하지만 단점이라고 한다면 컨트롤러가 많을 수록 설정해야하는 어노테이션이 많아진다는 것이다.

 

WebMvcConfigurer 에서 설정하기

 

해당 사용법도 간단하다.

 

Spring Initializer 를 이용해서 프로젝트를 만들었다면 다음과 같은 main 함수가 존재한다.

 

@SpringBootApplication
public class RestServiceCorsApplication {

    public static void main(String[] args) {
        SpringApplication.run(RestServiceCorsApplication.class, args);
    }
}

 

해당 main 함수에서 Bean 으로 Configurer 를 추가해주면 된다.

 

@SpringBootApplication
public class RestServiceCorsApplication {

    public static void main(String[] args) {
        SpringApplication.run(RestServiceCorsApplication.class, args);
    }

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedOrigins("http://front-server.com");
            }
        };
    }

}

 

물론 이 방법은 @Configuration 을 허용한 클래스에서 등록을 할 수도 있다.

 

 

참고 블로그 : https://wonit.tistory.com/572

 

 

댓글