Maison > Java > javaDidacticiel > le corps du texte

De quelle manière Springboot résout les problèmes inter-domaines CORS ?

王林
Libérer: 2023-05-13 16:55:06
avant
1454 Les gens l'ont consulté

1. Implémentez l'interface 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("*");
    }
}
Copier après la connexion

2. Implémentez la méthode de filtrage

@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);
    }
}
Copier après la connexion

3 L'annotation @CrossOrigin

@CrossOrigin(originPatterns = "*", allowCredentials = "true")
Copier après la connexion

@CrossOrigin peut être configurée sur la méthode ou sur la classe.

4. Combat pratique

Créez deux projets SpringBoot ordinaires A et B. A est configuré avec le port 8081 et B est configuré avec le port 8082.

Créez un fichier html index.html dans le répertoire resources/static de 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>
Copier après la connexion

B fournit 2 interfaces 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";
    }
}
Copier après la connexion

Démarrez respectivement les services A et B. Le navigateur accède au fichier index.html de A et clique sur le bouton La console du navigateur. signale l'erreur suivante : http://localhost:8081/index.html

L'accès à XMLHttpRequest à 'http://localhost:8082/hello/hello' depuis l'origine 'http://localhost:8081' a été bloqué par la politique CORS : Non 'Access- Control- L'en-tête Allow-Origin' est présent sur la ressource demandée.

De quelle manière Springboot résout les problèmes inter-domaines CORS ?

Méthode 1 pour le projet B, ajoutez le support inter-domaines, redémarrez, cliquez à nouveau sur le bouton, vous pouvez accéder normalement, observez qu'il y a plus d'en-têtes de réponse à prise en charge des informations inter-domaines :

De quelle manière Springboot résout les problèmes inter-domaines CORS ?

5. Cookies inter-domaines

À partir de Chrome 51, un nouvel attribut SameSite a été ajouté aux cookies du navigateur pour empêcher les attaques CSRF et le suivi des utilisateurs.

Valeurs possibles de SameSite : Strict, Lax, None.

Strict est le plus strict et interdit complètement les cookies tiers. En cas de cross-site, les cookies ne seront en aucun cas envoyés. En d’autres termes, ce n’est que si l’URL de la page Web actuelle est cohérente avec la cible de la requête que le cookie sera introduit.

Les règles laxistes sont légèrement assouplies et les cookies tiers ne sont pas envoyés dans la plupart des cas, à l'exception des requêtes Get qui redirigent vers l'URL cible. Les requêtes GET qui accèdent à une URL cible n'incluent que trois cas : les liens, les requêtes de préchargement et les formulaires GET.

Les sites Web peuvent choisir de désactiver explicitement l'attribut SameSite, en le définissant sur Aucun. Cependant, le principe est que l'attribut Secure doit être défini en même temps (les cookies ne peuvent être envoyés que via le protocole HTTPS), sinon il sera invalide.

SpringBoot 2.6 et supérieur

Configurations disponibles trouvées en ligne (mais les tests personnels ne sont pas valides !) :

server.servlet.session.cookie.same-site=none
server.servlet.session.cookie.secure=true
Copier après la connexion

SpringBoot 2.6 et inférieur

Si vous utilisez Tomcat comme serveur, vous pouvez définir des cookies de session via les éléments suivants Attribut de configuration SameSite (invalide en test personnel !).

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

Si vous utilisez Spring-Session, vous pouvez utiliser la configuration suivante pour définir l'attribut SameSite du cookie.

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

Votre propre solution

@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();
    }
}
Copier après la connexion
    @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";
    }
Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:yisu.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal