>  기사  >  Java  >  springboot가 CORS 도메인 간 문제를 해결하는 방법은 무엇입니까?

springboot가 CORS 도메인 간 문제를 해결하는 방법은 무엇입니까?

王林
王林앞으로
2023-05-13 16:55:061426검색

1. WebMvcConfigurer 인터페이스 구현

@Configuration
public class WebConfig implements WebMvcConfigurer {
    /**
     * 添加跨域支持
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 允许跨域访问的路径  '/**'表示应用的所有方法
        registry.addMapping("/**")
            // 允许跨域访问的来源 '*'表示所有域名来源
            .allowedOriginPatterns("*")
            // .allowedOrigins("*") // 允许跨域访问的来源 SpringBoot2.4.0之前的版本
            // 允许跨域请求的方法  '*'表示所有
            .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
            // 是否允许发送cookie true-允许 false-不允许 默认false。对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json,这个值只能设为true
            .allowCredentials(true)
            // 预检间隔时间1小时,单位为秒。指定本次预检请求的有效期,在有效期间,不用发出另一条预检请求。
            // 浏览器发出CORS简单请求,只需要在头信息之中增加一个Origin字段
            // 浏览器发出CORS非简单请求,会在正式通信之前,增加一次OPTIONS查询请求,称为"预检"请求(preflight)。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
            .maxAge(3600)
            // 允许跨域请求可携带的header,'*'表所有header头。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定
            .allowedHeaders("*");
    }
}

2. 필터 메소드 구현

@WebFilter
@Configuration
public class CorsFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        chain.doFilter(req, res);
    }
}

3. @CrossOrigin

@CrossOrigin(originPatterns = "*", allowCredentials = "true")

@CrossOrigin 주석은 메소드 또는 클래스에서 구성할 수 있습니다.

4. 실용적인 전투

두 개의 일반 SpringBoot 프로젝트 A와 B를 만듭니다. A는 포트 8081로 구성되고 B는 포트 8082로 구성됩니다.

A의 resources/static 디렉토리에 index.html이라는 HTML 파일을 만듭니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
 
<!-- jquery库可百度jquery cdn -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script>
    function btnClick() {
        $.get(&#39;http://localhost:8082/hello/hello&#39;, function (msg) {
            $("#app").html(msg);
        });
    }
 
    function btnClick2() {
        $.post(&#39;http://localhost:8082/hello/hello&#39;, function (msg) {
            $("#app").html(msg);
        });
    }
</script>
 
<body>
 
<div id="app"></div>
<input type="button" onclick="btnClick()" value="get_button">
<input type="button" onclick="btnClick2()" value="post_button">
 
</body>
</html>

B는 2개의 웹 인터페이스를 제공합니다.

@RestController
@RequestMapping("/hello")
public class HelloController {
    // @CrossOrigin(originPatterns = "*", allowCredentials = "true")
    @GetMapping("/hello")
    public String hello() {
        System.out.println("get hello");
        return "get hello";
    }
 
    // @CrossOrigin(originPatterns = "*", allowCredentials = "true")
    @PostMapping("/hello")
    public String hello2() {
        System.out.println("post hello");
        return "post hello";
    }
}

브라우저는 A의 index.html에 액세스하고 버튼을 클릭합니다. 다음 오류를 보고합니다: http://localhost:8081/index.html

원본 'http://localhost:8081'의 'http://localhost:8082/hello/hello'에서 XMLHttpRequest에 대한 액세스가 CORS 정책에 의해 차단되었습니다. 'Access- Control- 요청한 리소스에 Allow-Origin' 헤더가 있습니다.

springboot가 CORS 도메인 간 문제를 해결하는 방법은 무엇입니까?

프로젝트 B의 방법 1, 도메인 간 지원 추가, 다시 시작, 버튼을 다시 클릭하면 정상적으로 액세스할 수 있습니다. 교차 도메인 정보 지원:

springboot가 CORS 도메인 간 문제를 해결하는 방법은 무엇입니까?

5. 교차 도메인 쿠키

Chrome 51부터 CSRF 공격 및 사용자 추적을 방지하기 위해 SameSite라는 새로운 속성이 브라우저 쿠키에 추가되었습니다.

SameSite 가능한 값: Strict, Lax, None.

Strict는 가장 엄격하며 타사 쿠키를 완전히 금지합니다. 크로스 사이트에서는 어떤 상황에서도 쿠키가 전송되지 않습니다. 즉, 현재 웹페이지의 URL이 요청 대상과 일치하는 경우에만 쿠키를 가져옵니다.

Lax 규칙은 약간 완화되었으며 대상 URL로 이동하는 Get 요청을 제외하고 대부분의 경우 타사 쿠키가 전송되지 않습니다. 대상 URL로 이동하는 GET 요청에는 링크, 사전 로드 요청, GET 양식의 세 가지 경우만 포함됩니다.

웹사이트에서는 SameSite 속성을 명시적으로 꺼서 None으로 설정할 수 있습니다. 그러나 전제는 Secure 속성이 동시에 설정되어야 한다는 것입니다(쿠키는 HTTPS 프로토콜을 통해서만 전송될 수 있음). 그렇지 않으면 유효하지 않습니다.

SpringBoot 2.6 이상

온라인에서 찾을 수 있는 사용 가능한 구성(그러나 개인 테스트는 유효하지 않습니다!):

server.servlet.session.cookie.same-site=none
server.servlet.session.cookie.secure=true

SpringBoot 2.6 이하

Tomcat을 서버로 사용하는 경우 다음을 통해 세션 쿠키를 설정할 수 있습니다. 구성 SameSite 속성(개인 테스트에서는 유효하지 않습니다!)

server.servlet.session.cookie.secure=true
@Configuration
public class TomcatCookieConfig {
    @Bean
    public TomcatContextCustomizer sameSiteCookiesConfig() {
        return context -> {
            final Rfc6265CookieProcessor cookieProcessor = new Rfc6265CookieProcessor();
            // SameSite
            cookieProcessor.setSameSiteCookies(SameSiteCookies.NONE.getValue());
            context.setCookieProcessor(cookieProcessor);
        };
    }
}

Spring-Session을 사용하는 경우 다음 구성을 사용하여 쿠키의 SameSite 속성을 설정할 수 있습니다.

        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-core</artifactId>
        </dependency>
@Configuration
public class SpringSessionConfiguration {
    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        // Strict-严格模式 Lax-松懈模式 None-无
        cookieSerializer.setSameSite("None");
        cookieSerializer.setUseSecureCookie(true);
        return cookieSerializer;
    }
}

나만의 솔루션

@Configuration
public class CookieConfig {
    private static String domain;
 
    @Value("${domain}")
    public void setDomain(String domain) {
        CookieConfig.domain = domain;
    }
 
    public static HttpCookie generateHttpCookie(String name, String value) {
        return ResponseCookie.from(name, value)
            .domain(domain)
            // cookie跨域设置
            .sameSite("None")
            // 在https下传输,配合sameSite=None使用
            .secure(true)
            .path("/")
            // 有效期24小时
            .maxAge(60 * 60 * 24)
            .build();
    }
}
    @GetMapping("/hello")
    public String hello(HttpServletResponse response) {
        HttpCookie cookie2 = CookieConfig.generateHttpCookie("age", "18");
        response.addHeader(HttpHeaders.SET_COOKIE, cookie2.toString());
        HttpCookie cookie3 = CookieConfig.generateHttpCookie("id", "77");
        response.addHeader(HttpHeaders.SET_COOKIE, cookie3.toString());
        System.out.println("get hello");
        return "get hello";
    }

위 내용은 springboot가 CORS 도메인 간 문제를 해결하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제