• Springboot——解决跨域问题


    关于跨域介绍

    在前后分离的架构下,跨域问题难免会遇见比如,站点 http://domain-a.com 的某 HTML 页面通过 的 src 请求 http://domain-b.com/image.jpg。网络上的许多页面都会加载来自不同域的CSS样式表,图像和脚本等资源。

    出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求。 例如,XMLHttpRequest和Fetch API遵循同源策略。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非使用CORS头文件。

    跨域的体现,在于它的域名不同或者端口不同

    CORS(跨域源资源共享)(CORS,Cross-origin resource sharing)
    CORS是一个 W3C 标准,它是一份浏览器技术的规范,提供了 Web 服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,这是 JSONP 模式的现代版。

    情景复现

    建两个普通的 Spring Boot 项目,一个为 provider 提供服务,一个为 consumer 消费服务,第一个配置端口为 8080,第二个配置配置为 8081,然后在 provider 上提供两个 hello 接口,一个 get,一个 post,如下:

    @RestController
    public class HelloController {
        @GetMapping("/hello")
        public String hello() {
            return "hello";
        }
        @PostMapping("/hello")
        public String hello2() {
            return "post hello";
        }
    }
    

    在 consumer 的 resources/static 目录下创建一个 html 文件,发送一个简单的 ajax 请求,如下:

    <div id="app"></div>
    <input type="button" onclick="btnClick()" value="get_button">
    <input type="button" onclick="btnClick2()" value="post_button">
    <script>
        function btnClick() {
            $.get('http://localhost:8080/hello', function (msg) {
                $("#app").html(msg);
            });
        }
    
        function btnClick2() {
            $.post('http://localhost:8080/hello', function (msg) {
                $("#app").html(msg);
            });
        }
    </script>
    

    分别启动两个项目,发送请求按钮,观察浏览器控制台如下:

    Access to XMLHttpRequest at 'http://localhost:8080/hello' from origin 'http://localhost:8081' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
    

    由于同源策略的限制,请求无法发送成功。

    解决方案

    使用 CORS 可以在前端代码不做任何修改的情况下,实现跨域。在 provider 中配置。

    @CrossOrigin 注解配置(不推荐)

    注解配置某一个方法接受某一个域的请求,如下:

    @RestController
    public class HelloController {
        @CrossOrigin(value = "http://localhost:8081",maxAge = 3600)  //origin="*"代表所有域名都可访问  //maxAge飞行前响应的缓存持续时间的最大年龄,简单来说就是Cookie的有效期 单位为秒
    //若maxAge是负数,则代表为临时Cookie,不会被持久化,Cookie信息保存在浏览器内存中,浏览器关闭Cookie就消失
        @GetMapping("/hello")
        public String hello() {
            return "hello";
        }
    
        @CrossOrigin(value = "http://localhost:8081")
        @PostMapping("/hello")
        public String hello2() {
            return "post hello";
        }
    }
    

    这个注解表示这两个接口接受来自 http://localhost:8081 地址的请求,配置完成后,重启 provider ,再次发送请求,浏览器控制台就不会报错,consumer 也能拿到数据。

    此时浏览器请求网络控制台,可以看到响应头中多了如下信息:

    这个表示服务端愿意接收来自 http://localhost:8081 的请求,拿到这个信息后,浏览器就不会再去限制本次请求的跨域了。

    全局配置

    全局配置只需要在 SpringMVC 的配置类中重写 addCorsMappings 方法即可,如下:

    @Configuration
    public class WebMvcConfig implements WebMvcConfigurer {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
            .allowedOrigins("http://localhost:8081")
            .allowedMethods("*") //.allowedMethods("PUT", "DELETE","POST","GET")
            .allowedHeaders("*").maxAge(3600);
        }
    }
    

    /** 表示本应用的所有方法都会去处理跨域请求

    allowedMethods 表示允许通过的请求数

    allowedHeaders 则表示允许的请求头

    过滤器解决跨域

    可以把之前的三个方法的注解或者@Configuration都去掉

    @Configuration
    public class CrosFilter {
        @Bean
        CorsFilter getCorsFilter(){
            CorsConfiguration cors = new CorsConfiguration();
            cors.setAllowCredentials(true);
            cors.addAllowedMethod("*");
            cors.addAllowedOrigin("*");
            cors.setMaxAge(3600L);
            cors.addAllowedHeader("*");
            cors.applyPermitDefaultValues();
    
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**",cors);
    
            CorsFilter corsFilter = new CorsFilter(source);
            return corsFilter;
        }
    }
    

    存在的问题

    了解了整个 CORS 的工作过程之后,我们通过 Ajax 发送跨域请求,虽然用户体验提高了,但是也有潜在的威胁存在,常见的就是 CSRF(Cross-site request forgery)跨站请求伪造。跨站请求伪造也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF,是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法,举个例子:

    假如一家银行用以运行转账操作的URL地址如下:http://icbc.com/aa?bb=cc,那么,一个恶意攻击者可以在另一个网站上放置如下代码:,如果用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会遭受损失。

    基于此,浏览器在实际操作中,会对请求进行分类,分为简单请求,预先请求,带凭证的请求等,预先请求会首先发送一个 options 探测请求,和浏览器进行协商是否接受请求。默认情况下跨域请求是不需要凭证的,但是服务端可以配置要求客户端提供凭证,这样就可以有效避免 csrf 攻击。

  • 相关阅读:
    element input搜索框探索
    Github网站css加载不出来的处理方法(转,亲测有效)
    通过用axios发送请求,全局拦截请求,获取到错误弄明白promise对象
    vuex和localStorage/sessionStorage 区别
    leetcode刷题笔记十一 盛最多水的容器 Scala版本
    leetcode刷题笔记十 正则表达式 Scala版本
    leetcode刷题笔记九 回文数 Scala版本
    leetcode刷题笔记八 字符串转整性 Scala版本
    leetcode刷题笔记七 整数反转 Scala版本
    leetcode刷题笔记六 Z字型转换 Scala版本
  • 原文地址:https://www.cnblogs.com/luckyhui28/p/12355291.html
Copyright © 2020-2023  润新知