专栏首页玩转JavaEESpring Boot中通过CORS解决跨域问题

Spring Boot中通过CORS解决跨域问题

今天和小伙伴们来聊一聊通过CORS解决跨域问题。

同源策略

很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略。 同源策略是由Netscape提出的一个著名的安全策略,它是浏览器最核心也最基本的安全功能,现在所有支持JavaScript的浏览器都会使用这个策略。所谓同源是指协议、域名以及端口要相同。同源策略是基于安全方面的考虑提出来的,这个策略本身没问题,但是我们在实际开发中,由于各种原因又经常有跨域的需求,传统的跨域方案是JSONP,JSONP虽然能解决跨域但是有一个很大的局限性,那就是只支持GET请求,不支持其他类型的请求,而今天我们说的CORS(跨域源资源共享)(CORS,Cross-origin resource sharing)是一个W3C标准,它是一份浏览器技术的规范,提供了Web服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,这是JSONP模式的现代版。 在Spring框架中,对于CORS也提供了相应的解决方案,今天我们就来看看SpringBoot中如何实现CORS。

实践

接下来我们就来看看Spring Boot中如何实现这个东西。

首先创建两个普通的SpringBoot项目,这个就不用我多说,第一个命名为provider提供服务,第二个命名为consumer消费服务,第一个配置端口为8080,第二个配置配置为8081,然后在provider上提供两个hello接口,一个get,一个post,如下:

@RestControllerpublic 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注解配置某一个方法接受某一个域的请求,如下:

@RestControllerpublic class HelloController {    @CrossOrigin(value = "http://localhost:8081")    @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的请求,拿到这个信息后,浏览器就不会再去限制本次请求的跨域了。

provider上,每一个方法上都去加注解未免太麻烦了,在Spring Boot中,还可以通过全局配置一次性解决这个问题,全局配置只需要在配置类中重写addCorsMappings方法即可,如下:

@Configurationpublic class WebMvcConfig implements WebMvcConfigurer {    @Override    public void addCorsMappings(CorsRegistry registry) {        registry.addMapping("/**")        .allowedOrigins("http://localhost:8081")        .allowedMethods("*")        .allowedHeaders("*");    }}

/**表示本应用的所有方法都会去处理跨域请求,allowedMethods表示允许通过的请求数,allowedHeaders则表示允许的请求头。经过这样的配置之后,就不必在每个方法上单独配置跨域了。

存在的问题

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

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

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

好了,这个问题就说这么多,关于springboot中cors,还有一个小小的视频教程,加入我的知识星球免费观看。

本文分享自微信公众号 - 牧码小子(a_javaboy),作者:江南一点雨

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-03-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 九种跨域方式实现原理(完整版)

    前后端数据交互经常会碰到请求跨域,什么是跨域,以及有哪几种跨域方式,这是本文要探讨的内容。

    江南一点雨
  • Spring Boot2 系列教程(三十八)Spring Security 非法请求直接返回 JSON

    关于 Spring Security,松哥之前发过多篇文章和大家聊聊这个安全框架的使用:

    江南一点雨
  • 图书勘误-2

    江南一点雨
  • 白话http队头阻塞

    http协议的1.0版本与1.1版本最大的一个区别就是http1.1增加了长连接功能,那什么是http的长连接呢?

    挥刀北上
  • FPGA时序约束实战篇之主时钟约束

      在这一节开讲之前,我们先把wave_gen工程的wave_gen_timing.xdc中的内容都删掉,即先看下在没有任何时序约束的情况下会综合出什么结果?

    猫叔Rex
  • Cross-Origin Resource Sharing协议介绍

    传统的Ajax请求只能获取在同一个域名下面的资源,但是HTML5打破了这个限制,允许Ajax发起跨域的请求。浏览器是可以发起跨域请求的,比如你可以外链一个外域的...

    张善友
  • SpringMVC框架之第四篇

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    海仔
  • Java研发方向如何准备BAT技术面试答案(下)

    本文是针对文章《 Java研发方向如何准备BAT技术面试(超级干货)》里面的算法、数据结构、Linux和操作系统问题的一些答案。如有错误,还请各位网友指正。多谢...

    zhisheng
  • 虚拟货币减轻国家安全担忧

    人们把虚拟货币作为全球交换手段的兴趣从未如此之高。每种货币的日交易量已经突破了50亿美元。市场的流动性和全球性促使美国立法者举办听证会,在听证会上专家们仔细讨论...

    大黄大黄大黄
  • Netty学习三

    前面我们已经知道Netty服务端启动的时候最重要的是进行bind操作,这个操作不仅进行了run()操作进行死循环,而且将线程任务添加到队列中,进行runAllT...

    路行的亚洲

扫码关注云+社区

领取腾讯云代金券