Spring Boot 通过CORS实现跨域问题

 更新时间:2020年09月02日 08:10:22   作者:DOONDO  
这篇文章主要介绍了Spring Boot 通过CORS实现跨域,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

同源策略

很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略。

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

实践

首先,我们新建两个工程:

新建工程一:cors1 project

勾选Web模块 因为我们等下需要通过web接口进行测试 点击Finish完成构建

在cors1 中 我们新建一个HelloController,写上一个测试接口:

@RestController
public class HelloController {

  @GetMapping("/hello")
  public String hello(){
    return "hello cors1";
  }
}

新建工程二:cors2 project

对应的勾选Web模块进行构建。

在cors2的static目录下,建立Index.html,并编写一个GET请求按钮,发起Ajax请求(前提:static目录下有jquery.js)
请求cors1 工程的 localhost:8080/hello接口

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="jquery3.3.1.js"></script>
</head>
<body>
<div id="app"></div>
<input type="button" value="GET" onclick="getData()">
<input type="button" value="PUT" onclick="putData()">
<script>
  function getData() {
    $.get("http://localhost:8080/hello",function (msg) {
      $("#app").html(msg);
    })  
  }
</script>
</body>
</html>

并设定cors2 工程的项目端口:

server.port = 8081

分别启动cors1 和 cors2

访问 localhost:8081/index.html 点击按钮,发送请求:

访问报错,目前不支持跨域,验证了上面说的 同源策略

解决方案一:

1.在Controller类 或 接口方法上,使用 注解 @CrossOrigin 指定允许哪个域服务器访问

@RestController
public class HelloController {

  @GetMapping("/hello")
  @CrossOrigin(origins = "http://localhost:8081")
  public String hello(){
    return "hello cors1";
  }
}

重启 Cors1 项目,点击发送请求:

访问成功,浏览器控制台也没有报错

注意:
这种方式有一个弊端,就是我们需要在对外开放的每个接口或者类上都要写一遍,大大增加了开发的重复性和繁琐性

解决方案二

Spring Boot 中,可以通过全局配置一次性解决这个问题,全局配置只需要在 SpringMVC 的配置类中重写 **addCorsMappings **方法即可

package org.taoguoguo;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author taoguoguo
 * @description WebMvcConfig
 * @website https://www.cnblogs.com/doondo
 * @create 2020-09-01 21:31
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

  /**
   * 跨域全局配置
   * @param registry
   */
  @Override
  public void addCorsMappings(CorsRegistry registry) {
    //addMapping 允许哪些接口跨域
    //allowedOrigins 允许哪个域服务器访问
    //allowedHeaders 允许通过的请求头
    //maxAge 服务器在发送一些请求(例如put)会先发一个探测请求,避免每次都需要发送探测请求 可以设置有效期
    registry.addMapping("/**")
        .allowedOrigins("http://localhost:8081")
        .allowedHeaders("*")
        .allowedMethods("*")
        .maxAge(30*1000);
  }
}

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

现在再去页面访问,也是没有问题的

探测请求

我们在跨域设置中

maxAge 服务器在发送一些请求(例如put)会先发一个探测请求,避免每次都需要发送探测请求 可以设置有效

先举一个例子:
我们在Cors1中添加一个put请求

@RestController
public class HelloController {

  @GetMapping("/hello")
  @CrossOrigin(origins = "http://localhost:8081")
  public String hello(){
    return "hello cors1";
  }

  @PutMapping("/doput")
  public String doput(){
    return "doput";
  }
}

在cors2中增加put请求发送按钮

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="jquery3.3.1.js"></script>
</head>
<body>
<div id="app"></div>
<input type="button" value="GET" onclick="getData()">
<input type="button" value="PUT" onclick="putData()">
<script>
  function getData() {
    $.get("http://localhost:8080/hello",function (msg) {
      $("#app").html(msg);
    })
  }
  
  function putData() {
    $.ajax({
      type:'put',
      url: 'http://localhost:8080/doput',
      success:function (msg) {
        $("#app").html(msg);
      }
    })
    
  }
</script>
</body>
</html>

启动cors1 cors2 发送put请求:

我们看到请求一次 浏览器会发送两次请求,其中Request Methods 为 options 的即为探测请求
因为我们设置了探测请求的有效期,因此当我们再次发送时,浏览器只会发送一次请求

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

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

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

总结

到此这篇关于Spring Boot 通过CORS实现跨域问题的文章就介绍到这了,更多相关Spring Boot实现跨域内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springboot中RabbitMQ死信队列的实现示例

    springboot中RabbitMQ死信队列的实现示例

    死信队列是一种特殊的消息队列,用来存储无法被正常消费的消息,常被用来实现延迟处理,异常消息处理等,本文主要介绍了springboot中RabbitMQ死信队列的实现示例,感兴趣的可以了解一下
    2024-01-01
  • java之this关键字用法实例分析

    java之this关键字用法实例分析

    这篇文章主要介绍了java之this关键字用法实例分析,较为详细的讲述了Java中this关键字的用法及适用范围,并附带实例程序加以说明,需要的朋友可以参考下
    2014-09-09
  • Java多线程编程之ThreadLocal线程范围内的共享变量

    Java多线程编程之ThreadLocal线程范围内的共享变量

    这篇文章主要介绍了Java多线程编程之ThreadLocal线程范围内的共享变量,本文讲解了ThreadLocal的作用和目的、ThreadLocal的应用场景、ThreadLocal的使用实例等,需要的朋友可以参考下
    2015-05-05
  • Java实现UDP互发消息

    Java实现UDP互发消息

    这篇文章主要为大家详细介绍了Java实现UDP互发消息,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • springboot 基于Tomcat容器的自启动流程分析

    springboot 基于Tomcat容器的自启动流程分析

    这篇文章主要介绍了springboot 基于Tomcat容器的自启动流程分析,Spring通过注解导入Bean大体可分为四种方式,我们主要来说Import的两种实现方法,需要的朋友可以参考下
    2020-02-02
  • 深入理解Java线程池从设计思想到源码解读

    深入理解Java线程池从设计思想到源码解读

    这篇文章主要介绍了深入理解Java线程池从设计思想到源码解读,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • Java dom4j创建解析xml文档过程解析

    Java dom4j创建解析xml文档过程解析

    这篇文章主要介绍了Java dom4j创建解析xml文档过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • java开发分布式服务框架Dubbo暴露服务过程详解

    java开发分布式服务框架Dubbo暴露服务过程详解

    这篇文章主要为大家介绍了java开发分布式服务框架Dubbo暴露服务的过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2021-11-11
  • Spring Boot 整合 Reactor实例详解

    Spring Boot 整合 Reactor实例详解

    这篇文章主要为大家介绍了Spring Boot 整合 Reactor实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • java实现登录验证码

    java实现登录验证码

    这篇文章主要为大家详细介绍了java实现登录验证码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-06-06

最新评论