Rumah  >  Artikel  >  Java  >  Apakah cara springboot menyelesaikan isu merentas domain CORS?

Apakah cara springboot menyelesaikan isu merentas domain CORS?

王林
王林ke hadapan
2023-05-13 16:55:061380semak imbas

1. Laksanakan antara muka 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 Laksanakan kaedah penapis

@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 Anotasi @CrossOrigin

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

@CrossOrigin boleh dikonfigurasikan. serta Boleh dikonfigurasikan pada kelas.

4. Pertempuran praktikal

Buat dua projek SpringBoot biasa A dan B. A dikonfigurasikan dengan port 8081 dan B dikonfigurasikan dengan port 8082.

Buat fail html index.html dalam direktori sumber/statik A:

<!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 menyediakan 2 antara muka web:

@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";
    }
}

Mulakan perkhidmatan A dan B masing-masing A's index.html dan mengklik butang Konsol penyemak imbas melaporkan ralat berikut: http://localhost:8081/index.html

Akses kepada XMLHttpRequest di 'http://localhost:8082/hello/hello' dari asal 'http. ://localhost:8081' telah disekat oleh dasar CORS: Tiada pengepala 'Access-Control-Allow-Origin' hadir pada sumber yang diminta.

Apakah cara springboot menyelesaikan isu merentas domain CORS?

Untuk kaedah pertama menggunakan projek B, tambah sokongan merentas domain, mulakan semula, klik butang sekali lagi dan anda boleh mengaksesnya seperti biasa Perhatikan bahawa pengepala respons mempunyai lebih banyak maklumat sokongan merentas domain:

Apakah cara springboot menyelesaikan isu merentas domain CORS?

5. Kuki merentas domain

Bermula dari Chrome 51, atribut SameSite baharu telah ditambahkan pada kuki penyemak imbas untuk menghalang serangan CSRF dan penjejakan pengguna.

Nilai yang mungkin SameSite: Tegas, Longgar, Tiada.

Strict adalah yang paling ketat dan melarang sepenuhnya kuki pihak ketiga tidak akan dihantar dalam apa jua keadaan apabila melintasi tapak. Dalam erti kata lain, hanya jika URL halaman web semasa adalah konsisten dengan sasaran permintaan, kuki akan dibawa.

Peraturan longgar dilonggarkan sedikit dan kuki pihak ketiga tidak dihantar dalam kebanyakan kes, kecuali untuk Dapatkan permintaan yang menavigasi ke URL sasaran. Permintaan GET yang menavigasi ke URL sasaran hanya termasuk tiga kes: pautan, permintaan pramuat dan borang GET.

Tapak web boleh memilih untuk mematikan atribut SameSite secara eksplisit, menetapkannya kepada Tiada. Walau bagaimanapun, premisnya ialah atribut Secure mesti ditetapkan pada masa yang sama (Kuki hanya boleh dihantar melalui protokol HTTPS), jika tidak, ia akan menjadi tidak sah.

SpringBoot 2.6 dan ke atas

Konfigurasi yang tersedia ditemui dalam talian (tetapi ujian peribadi tidak sah!):

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

SpringBoot 2.6 atau di bawah Versi

Jika anda menggunakan Tomcat sebagai pelayan, anda boleh menetapkan atribut SameSite bagi kuki sesi melalui konfigurasi berikut (ujian peribadi tidak berfungsi!).

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);
        };
    }
}

Jika anda menggunakan Spring-Session, maka anda boleh menggunakan konfigurasi berikut untuk menetapkan atribut SameSite bagi kuki.

        <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;
    }
}

Penyelesaian saya sendiri

@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";
    }

Atas ialah kandungan terperinci Apakah cara springboot menyelesaikan isu merentas domain CORS?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam