SpringBoot 2.7+ CORS ์ด์Šˆ ๋ฐ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•

    ๋ฐ˜์‘ํ˜•

    ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“  API ์„œ๋ฒ„๋ฅผ ํ…Œ์ŠคํŠธ ํ•˜๊ธฐ ์œ„ํ•ด ๋กœ์ปฌ์—์„œ ๋Œ๋ฆฌ๋˜ ๋„์ค‘ ํ•ด๋‹น ์ด์Šˆ๋ฅผ ๋งŒ๋‚ฌ๋‹ค.

    ๊ตฌ์„ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

    1. localhost:8080/users - SpringBoot API Server ์—์„œ ์œ ์ € ๋ฐ์ดํ„ฐ๋ฅผ ๋ฆฌํ„ด.
    2. localhost:8090/index.html - API์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์žˆ๋Š” html ํŽ˜์ด์ง€
    index.html
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    
    </head>
    
    <body>
        <div id="app">
            {{ message }}
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    message: '์•ˆ๋…•ํ•˜์„ธ์š” Vue!'
                },
                created: function () {
                    var vm = this;
                    vm.test();
                },
                methods: {
                    test: function () {
                        axios.post('http://localhost:8080/users', {
                            params: ''
                        })
                            .then(function (response) {
                                console.log(response);
                            })
                            .catch(function (error) {
                                console.log(error);
                            });
                    }
                }
            })
        </script>
    </body>
    
    </html>

    ๊ฐ„๋‹จํ•˜๊ฒŒ nginx Docker๋กœ ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ 8090ํฌํŠธ๋กœ ๋„์› ๋‹ค.

    FROM nginx:alpine
    COPY . /usr/share/nginx/html

     

    ๊ทธ๋ฆฌ๊ณ  ๋Œ€๋ง์˜ CORS ์ด์Šˆ๋ฅผ ๋งŒ๋‚ฌ๋‹ค.

    CORS ์ด์Šˆ

    ๊ทธ๋ฆฌ๊ณ  ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๊ฒ€์ƒ‰ํ•ด๋ณธ ๊ฒฐ๊ณผ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

    ์ œ์ผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋‚ด ํ™”๋ฉด์—์„œ๋งŒ ์•ˆ๋‚˜์˜ค๊ฒŒ ํ•˜๊ณ ์‹ถ๋‹ค!

    https://chrome.google.com/webstore/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf?hl=ko 

     

    Allow CORS: Access-Control-Allow-Origin

    Easily add (Access-Control-Allow-Origin: *) rule to the response header.

    chrome.google.com

    ํ•ด๋‹น ํ™•์žฅํ”„๋กœ๊ทธ๋žจ์„ ๊น”๋ฉด ์•Œ์•„์„œ ํ•ด๋‹น ์ด์Šˆ๊ฐ€ ์•ˆ๋‚˜์˜ค๋„๋ก ์„ค์ •ํ•ด์ค€๋‹ค. ๋‚ด ํ™˜๊ฒฝ์—์„œ๋งŒ ์˜ค๋ฅ˜๋ฅผ ์•ˆ๋‚˜๊ฒŒ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ด๋ ‡๊ฒŒ ํ•ด๋„ ์ƒ๊ด€ ์—†๋‹ค.(๋ฌผ๋ก  ํฌ๋กฌ ํ•œ์ •)

    SpringBoot์—์„œ AllowOrigin ํ•˜๋Š” ๋ฐฉ๋ฒ•

    ์ฒซ๋ฒˆ์งธ๋Š” Spring Boot ์—์„œ WebMvcConfigurer๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ—ˆ์šฉํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.
    ํ•ด๋‹น ๋ฐฉ์‹์€ Config ์™ธ์—๋„ @CrossOrigin ์ด๋ผ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ์ปจํŠธ๋กค๋Ÿฌ ๋งˆ๋‹ค ์„ค์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

    ์šฐ์„  ์†Œ์Šค๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์ ์šฉํ–ˆ๋‹ค.

    package rest.api.sample.config;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.CorsRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                    .allowedOrigins("*")
                    .allowedMethods("GET", "POST")
                    .maxAge(3000);
        }
    }

     

    ์„œ๋ฒ„์— ์œ„ ์†Œ์Šค๋ฅผ ์ ์šฉํ•˜๊ณ  ๋Œ๋ ค๋ณด๋‹ˆ, ๋ธŒ๋ผ์šฐ์ €๋งˆ๋‹ค ๋ฐ˜์‘์ด ๋‹ฌ๋ž๋Š”๋ฐ ํฌ๋กฌ์€ ์—ฌ์ „ํžˆ CORS ์ด์Šˆ ๋•Œ๋ฌธ์— ์‘๋‹ต์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅ ํ–ˆ๊ณ , ์‚ฌํŒŒ๋ฆฌ์—์„œ๋Š” ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

    ๊ทธ๋ ‡๋‹ค๊ณ  ์‚ฌํŒŒ๋ฆฌ์—์„œ๋งŒ ํ•  ์ˆ˜๋„ ์—†๋Š” ๋…ธ๋ฆ‡์ด๋ผ ๋” ์ฐพ์•„๋ณด๋‹ˆ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ธ€์„ ์ฐพ๊ฒŒ ๋˜์—ˆ๋‹ค.

    https://howtolivelikehuman.tistory.com/191

     

    Spring Boot CORS header 'Access-Control-Allow-Origin' ์—๋Ÿฌ

    Spring Boot๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ Rest API ๋ฐฉ์‹์„ ๊ตฌํ˜„ํ•˜๋‹ค๋ณด๋ฉด, Postman๊ฐ™์€ ํ”„๋กœ๊ทธ๋žจ์—์„œ๋Š” ์ž˜๋งŒ ์ž‘๋™๋˜๋Š”๋ฐ ์‹ค์ œ ์‹คํ–‰์—์„œ๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค. React (Node.js) : http://localhost:3000 Spring boot : http..

    howtolivelikehuman.tistory.com

     

    ์‚ดํŽด๋ณด๋‹ˆ ๋™์ผํ•˜๊ฒŒ ๋ฐœ์ƒํ•˜๋Š” ์ƒํ™ฉ์ด์—ˆ๊ณ  ์œ„ ์ฒ˜๋Ÿผ ์„ค์ •์„ ์ ์šฉํ•ด๋„ ํ•  ์ˆ˜ ์—†์—ˆ๋‹ค๊ณ  ํ•˜๋ฉฐ, SpringSecurity์˜ WebSecurityConfigurerAdaptor๋ฅผ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ํ–ˆ๋‹ค.

    ํ•˜์—ฌ ์ ์šฉ ๊ฐ€๋Šฅํ•œ๊ฐ€ ์‚ดํŽด๋ณด๋‹ˆ ๋ฒ„์ „ ์ด์Šˆ๊ฐ€ ์žˆ์—ˆ๋‹ค. ๋ฐ”๋กœ SpringBoot 2.7 ์ด์ƒ ๋ฒ„์ „์—์„œ๋Š” ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋‹ค๋Š” ๊ฒƒ.

    https://honeywater97.tistory.com/264

     

    [SpringBoot] WebSecurityConfigurerAdapter ์ง€์› ๋ถˆ๊ฐ€

    ํ™˜๊ฒฝ - SpringBoot 2.7 - Java17 - Spring Security //spring security implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.security.oauth.boot:spri..

    honeywater97.tistory.com

     

    ๊ทธ๋ž˜์„œ ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํ•„ํ„ฐ๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ์ด์Šˆ๋ฅผ ํ•ด๊ฒฐํ•˜์˜€๋‹ค๊ณ  ํ•˜์˜€๋‹ค.

    ๋”ฐ๋ผ์„œ, CORS ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•œ ์‚ฌ๋ก€๋ฅผ ์ฐพ์•„๋ณด์•˜๋‹ค.

    CORS Filter๋ฅผ ์ด์šฉํ•œ ๋ฐฉ๋ฒ•

    CorsFilter.java
    package rest.api.sample.config;
    
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    @Component
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public class CorsFilter implements Filter {
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
                throws IOException, ServletException {
            HttpServletResponse response = (HttpServletResponse) res;
            HttpServletRequest request = (HttpServletRequest) req;
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Credentials", "true");
            response.setHeader("Access-Control-Allow-Methods",
                    "ACL, CANCELUPLOAD, CHECKIN, CHECKOUT, COPY, DELETE, GET, HEAD, LOCK, MKCALENDAR, MKCOL, MOVE, OPTIONS, POST, PROPFIND, PROPPATCH, PUT, REPORT, SEARCH, UNCHECKOUT, UNLOCK, UPDATE, VERSION-CONTROL");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Headers",
                    "Origin, X-Requested-With, Content-Type, Accept, Key, Authorization");
    
            if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
                response.setStatus(HttpServletResponse.SC_OK);
            } else {
                chain.doFilter(req, res);
            }
        }
    
        public void init(FilterConfig filterConfig) {
            // not needed
        }
    
        public void destroy() {
            // not needed
        }
    
    }

     

    ํ•ด๋‹น ์†Œ์Šค๋Š” ์•„๋ž˜ ๊ธ€์—์„œ ์ฐพ์•˜๋‹ค.

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

     

    Spring security CORS Filter

    We added Spring Security to our existing project. From this moment on we get a 401 No 'Access-Control-Allow-Origin' header is present on the requested resource error from the our server. That's bec...

    stackoverflow.com

     

    ์œ„ ํ•„ํ„ฐ๋ฅผ ์ ์šฉ ํ›„ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด์•˜๋‹ค.

    CORS ์ด์Šˆ ์—†์ด ์„ฑ๊ณต!

     

    ๊ฒฐ๊ณผ๋Š” ์ž˜ ๋‚˜์˜ค๋Š” ๊ฒƒ์œผ๋กœ ํ™•์ธ ๋˜์—ˆ๋‹ค.

    ์™œ WebConfigurer ์„ค์ •์œผ๋กœ๋Š” ์•ˆ๋˜๊ณ  ํ•„ํ„ฐ์—์„œ ์„ฑ๊ณต์„ ํ•˜์˜€๋‚˜ ์‚ดํŽด๋ณด๋‹ˆ ๋ฌธ์ œ๋Š” Response์˜ ํ—ค๋”์— ์žˆ์—ˆ๋‹ค. ์œ„์— ์—๋Ÿฌ์—์„œ ๋‚˜์˜จ๋Œ€๋กœ
    "CORS(Cross-Origin Resource Sharing)๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด header์— ๋ณด๋‚ด๋Š” ํ‚ค(Access-Control-Allow-Origin)์ด ์—†๋‹ค" ๋Š” ๊ฒƒ์ด์—ˆ๋‹ค.

    ๋”ฐ๋ผ์„œ ํ•„ํ„ฐ ์ชฝ์—์„œ Response์˜ ์‘๋‹ต ํ—ค๋”์— ํ•ด๋‹น ๊ฐ’์„ ์„ธํŒ…ํ•ด ์คŒ์œผ๋กœ์จ ํฌ๋กฌ์—์„œ๋„ ํ•ด๋‹น ์ด์Šˆ๋ฅผ ์žก์ง€ ์•Š๋„๋ก ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅ ํ–ˆ๋‹ค.
    ํ•ด๋‹น ํ•„ํ„ฐ๋Š” ํ•˜๋‚˜์ฏค ์„ธํŒ…ํ•ด๋‘๊ณ  on/off ๋˜๋Š” ์ฃผ์„ ์ฒ˜๋ฆฌ๋ฅผ ํ†ตํ•ด ์„ธํŒ…ํ•˜๋Š” ๊ฒƒ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ์ข‹๊ฒ ๋‹ค.

     

    728x90
    ๋ฐ˜์‘ํ˜•

    ๋Œ“๊ธ€