๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
  • ์žฅ์›์ต ๊ธฐ์ˆ ๋ธ”๋กœ๊ทธ
๐Ÿ’Š Java & Kotlin & Spring/- spring framework +

[Spring Boot] CORS ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” 3๊ฐ€์ง€ ๋ฐฉ๋ฒ• (Filter, @CrossOrigin, WebMvcConfigurer)

by Wonit 2021. 8. 14.

 

Server Side Template ๋ฐฉ์‹์ด ์•„๋‹Œ Front์™€ Back ์œผ๋กœ ๋‚˜๋ˆ ์„œ ์ธํ”„๋ผ๋ฅผ ๊ตฌ์„ฑํ•ด๋ณธ ๊ฒฝํ—˜์ด ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค์—๊ฒŒ๋Š” Cors๊ฐ€ ๋งค์šฐ ์นœ์ˆ™ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

ํ˜„์žฌ ๊ฐœ๋ฐœ ํ๋ฆ„์—์„œ ์›น ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋‹ค๊ฐ€ Cors ๋ฅผ ๋งŒ๋‚  ํ™•๋ฅ ์€ ๊ฐ€ํžˆ 100% ๋ผ๊ณ  ํ•ด๋„ ๊ณผ์–ธ์ด ์•„๋‹ˆ๋‹ค.

 

์˜ค๋Š˜์€ CORS ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•Œ์•„๋ณด๋ฉฐ ๋˜, Spring Boot Application ์—์„œ๋Š” ์–ด๋–ป๊ฒŒ ํ•ด๋‹น ์ •์ฑ…์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ์•„๋ณด์ž.

 

CORS ํ•ด๊ฒฐํ•˜๊ธฐ

 

์šฐ์„  ๊ฐ€์žฅ ๋จผ์ € ๋ง ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์€

 

CORS ๋Š” ์—๋Ÿฌ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹ˆ๋‹ค. Cross-Origin Resource Sharing Policy ์ด๋‹ค.

 

์ฒ˜์Œ ๋‚ด๊ฐ€ Front ์™€ Back ์„ ๋‚˜๋ˆ ์„œ ๊ฐœ๋ฐœ์„ ํ•  ๋•Œ์—๋Š” ๋‹จ์ˆœํžˆ Front ์—์„œ fetch ์š”์ฒญ์œผ๋กœ Back ์„ ๋ฐ”๋ผ๋ณด๊ณ  ๋‚ ๋ฆฌ๋ฉด ๋ ์ค„ ์•Œ์•˜๋Š”๋ฐ, ์œ„์—์„œ ๋ณด์ด๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ์— ์ •๋ง ์งœ์ฆ๋‚˜๊ณ  ๊ท€์ฐฎ์€ ์—๋Ÿฌ ์ฏค ์œผ๋กœ ์ƒ๊ฐ์„ ํ–ˆ์—ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ CORS ๋Š” ๊ท€์ฐฎ์„ ๋ฟ ํ•˜๋‚˜์˜ ๋ณด์•ˆ ์ •์ฑ…์ด๋‹ค.

 

CORS ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์ด์•ผ๊ธฐ๋Š” ํ•ด๋‹น ๋ธ”๋กœ๊ทธ Cross Origin Resource Sharing ์ด๋ž€? ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ด๋Ÿฌํ•œ ๋ณด์•ˆ ์ •์ฑ…์ด ๋ฐœ์ƒํ•˜๋Š” ์ด์œ ๋ฅผ ๊ฐ„๋‹จํžˆ ์ด์•ผ๊ธฐ ํ•˜์ž๋ฉด, SOP ๋•Œ๋ฌธ์ด๋‹ค.

 

SOP ๋ž€?

 

SOP ๋Š” Same Origin Policy ๋กœ, ๋™์ผํ•œ ์ถœ์ฒ˜์˜ Origin ๋งŒ ๋ฆฌ์†Œ์Šค(๋ฐ์ดํ„ฐ)๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

 

๋งŒ์•ฝ ๋™์ผํ•œ ์ถœ์ฒ˜๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด OPTIONS ๋ฅผ ์ด์šฉํ•œ Preflight ๋ฅผ ์ด์šฉํ•ด์„œ ์—ฌ๋Ÿฌ ๊ฒ€์ฆ์„ ๊ฑฐ์น˜๊ฒŒ ๋˜๋Š”๋ฐ,

 

OPTIONS์™€ Preflight ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์‚ฌํ•ญ์€ ํ•ด๋‹น ๋ธ”๋กœ๊ทธ์˜ HTTP OPTIONS ํ—ค๋”์™€ Preflight ๊ทธ๋ฆฌ๊ณ  CORS ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ด ๊ฒ€์ฆ์ด ๋ฐ”๋กœ Cors ์ธ ๊ฒƒ์ด๋‹ค.

 

CORS ์˜ ๊ฐ„๋‹จ ํ”Œ๋กœ์šฐ๋Š”?

 

์šฐ๋ฆฌ๊ฐ€ Front Back ๊ตฌ์กฐ์—์„œ SOP ๋ฅผ ์œ„๋ฐ˜ํ•˜๊ณ , ์ ์ ˆํ•œ ๋ณด์•ˆ ์ธ์ฆ์„ ๋ฐ›๊ธฐ ์œ„ํ•ด์„œ ๋ธŒ๋ผ์šฐ์ €๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ณผ์ •์„ ๊ฑฐ์น˜๊ฒŒ ๋œ๋‹ค.

 

 

  1. GET ์š”์ฒญ์ธ์ง€ POST ์š”์ฒญ์ธ์ง€ ํŒŒ์•…ํ•œ๋‹ค.
  2. Content-Type ๊ณผ Custom HTTP Header ๋ฅผ ํŒŒ์•…ํ•œ๋‹ค.
  3. OPTIONS ์š”์ฒญ์„ ํ†ตํ•ด์„œ ์„œ๋ฒ„๊ฐ€ ์ ์ ˆํ•œ Access-Control-* ๋ฅผ ๊ฐ€์กŒ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
  4. ๋งŒ์•ฝ ์ ์ ˆํ•œ Access-Control ์„ ๊ฐ€์กŒ๋‹ค๋ฉด ์‹ค์ œ XHR์„ ํŠธ๋ฆฌ๊ฑฐํ•œ๋‹ค.
  5. ์ ์ ˆํ•˜์ง€ ๋ชปํ•œ Access-Control ๋ฅผ ๊ฐ€์กŒ๋‹ค๋ฉด Error ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

 

์ด ํ”Œ๋กœ์šฐ์—์„œ ์ ์ ˆํ•œ ๋Œ€์ฒ˜๋ฅผ ํ•˜์ง€ ๋ชปํ•œ๋‹ค๋ฉด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ด ๋งจ ์œ„์—์„œ ๋ณธ CORS ์—๋Ÿฌ์ธ ๊ฒƒ์ด๋‹ค.

 

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‹ค์ œ Spring Boot Application ์œผ๋กœ ๋“ค์–ด๊ฐ€๋ณด์ž.

 

Spring Boot Application ์—์„œ CORS ํ•ด๊ฒฐํ•˜๊ธฐ

 

๋ณธ์ธ์ด ๋งŒ์•ฝ ์–ด๋–ค API ์„œ๋ฒ„๋“  ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด ๊ทธ ์„œ๋ฒ„๋กœ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” ํ˜„์žฌ ํŒ€ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉ์ค‘์ธ API ์„œ๋ฒ„๋ฅผ ๋งˆ์นจ CORS ์ด์Šˆ๋ฅผ ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ์„œ๋ฒ„๋กœ ์‹ค์Šต์„ ์ด์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๋ณธ๋ก ์œผ๋กœ ๋Œ์•„๊ฐ€์„œ CORS ๋Š” ์™œ ๋ฐœ์ƒํ•œ๋‹ค๊ณ  ํ–ˆ๋Š”์ง€ ์ƒ๊ฐํ•ด๋ณด์ž.

 

Preflight ์š”์ฒญ์—์„œ ์ ์ ˆํ•œ Access-Control ์„ ํ™•์ธํ•˜์ง€ ๋ชปํ•˜๋ฉด ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค!

 

์ด๋Ÿฐ 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 ์„ ํ—ˆ์šฉํ•œ ํด๋ž˜์Šค์—์„œ ๋“ฑ๋ก์„ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 

๋Œ“๊ธ€