๐Ÿ”ฅError

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

harry.93 2022. 7. 7. 00:40
๋ฐ˜์‘ํ˜•

๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“  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
๋ฐ˜์‘ํ˜•