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

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

王林
王林avant
2023-05-13 16:55:061426parcourir

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("*");
    }
}

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

3 L'annotation @CrossOrigin

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

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

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

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

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
@Configuration
public class TomcatCookieConfig {
    @Bean
    public TomcatContextCustomizer sameSiteCookiesConfig() {
        return context -> {
            final Rfc6265CookieProcessor cookieProcessor = new Rfc6265CookieProcessor();
            // SameSite
            cookieProcessor.setSameSiteCookies(SameSiteCookies.NONE.getValue());
            context.setCookieProcessor(cookieProcessor);
        };
    }
}

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>
@Configuration
public class SpringSessionConfiguration {
    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        // Strict-严格模式 Lax-松懈模式 None-无
        cookieSerializer.setSameSite("None");
        cookieSerializer.setUseSecureCookie(true);
        return cookieSerializer;
    }
}

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

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer