Heim  >  Artikel  >  Java  >  Auf welche Weise löst Springboot domänenübergreifende CORS-Probleme?

Auf welche Weise löst Springboot domänenübergreifende CORS-Probleme?

王林
王林nach vorne
2023-05-13 16:55:061457Durchsuche

1. Implementieren Sie die WebMvcConfigurer-Schnittstelle

@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. Implementieren Sie die Filterfiltermethode

@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. Annotation@CrossOrigin

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

@ CrossOrigin kann für die Methode oder die Klasse konfiguriert werden.

4. Praktischer Kampf

Erstellen Sie zwei normale SpringBoot-Projekte A und B. A ist mit Port 8081 und Port B mit Port 8082 konfiguriert.

Erstellen Sie eine HTML-Datei index.html im Verzeichnis resources/static von 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 bietet 2 Webschnittstellen:

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

bzw. Starten Sie Dienste A und B. Der Browser greift auf die Datei index.html von A zu und klickt auf die Schaltfläche. Die Browserkonsole meldet den folgenden Fehler: 8082/hello/hello“ vom Ursprung „http://localhost:8081“ wurde durch die CORS-Richtlinie blockiert: Auf der angeforderten Ressource ist kein „Access-Control-Allow-Origin“-Header vorhanden.http://localhost:8081/index.html#🎜 🎜#

Fügen Sie für Projekt B domänenübergreifende Unterstützung hinzu, starten Sie neu, klicken Sie erneut auf die Schaltfläche, Sie können normal darauf zugreifen und beobachten, dass es weitere Antwortheader gibt, die domänenübergreifend unterstützen. Domäneninformationen:

Auf welche Weise löst Springboot domänenübergreifende CORS-Probleme?

5. Domänenübergreifendes Cookie

Ab Chrome51 fügt das Browser-Cookie ein neues Attribut „SameSite“ hinzu Verhindern Sie CSRF-Angriffe und Benutzerverfolgung. Auf welche Weise löst Springboot domänenübergreifende CORS-Probleme?

SameSite Mögliche Werte: Streng, Lax, Keine.

Strikt ist die strengste Einstellung und verbietet Cookies von Drittanbietern vollständig. Bei Cross-Site werden unter keinen Umständen Cookies gesendet. Mit anderen Worten: Nur wenn die URL der aktuellen Webseite mit dem Anforderungsziel übereinstimmt, wird das Cookie abgerufen.

Laxe Regeln sind etwas gelockert und Cookies von Drittanbietern werden in den meisten Fällen nicht gesendet, außer bei Get-Anfragen, die zur Ziel-URL navigieren. Eine GET-Anfrage, die zu einer Ziel-URL navigiert, umfasst nur drei Fälle: Link, Preload-Anfrage und GET-Formular.

Websites können das SameSite-Attribut explizit deaktivieren und es auf „None“ setzen. Voraussetzung ist jedoch, dass gleichzeitig das Secure-Attribut festgelegt werden muss (Cookies können nur über das HTTPS-Protokoll gesendet werden), andernfalls ist es ungültig.

SpringBoot 2.6 und höher

Verfügbare Konfigurationen online gefunden (jedoch nicht für persönliche Tests gültig!):

server.servlet.session.cookie.same-site=none
server.servlet.session.cookie.secure=true
#🎜 🎜 #SpringBoot-Versionen unter 2.6

Wenn Sie Tomcat als Server verwenden, können Sie das SameSite-Attribut des Sitzungscookies über die folgende Konfiguration festlegen (persönlicher Test funktioniert nicht! ).

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

Wenn Sie Spring-Session verwenden, können Sie die folgende Konfiguration verwenden, um das SameSite-Attribut des Cookies festzulegen.

        <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;
    }
}
eigene Lösung

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

Das obige ist der detaillierte Inhalt vonAuf welche Weise löst Springboot domänenübergreifende CORS-Probleme?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen