Web端系统开发解决跨域问题——以Java SpringBoot框架配置Cors为例

本文涉及的产品
.cn 域名,1个 12个月
简介: 在Web安全上下文中,源(Origin)是指一个URL的协议、域名和端口号的组合。这三个部分共同定义了资源的来源,浏览器会根据这些信息来判断两个资源是否属于同一源。例如,https://www.example.com:443和http://www.example.com虽然域名相同,但由于协议和端口号不同,它们被视为不同的源。同源(Same-Origin)是指两个URL的协议、域名和端口号完全相同。只有当这些条件都满足时,浏览器才认为这两个资源来自同一源,从而允许它们之间的交互操作。

在Web端系统开发中,跨域问题是一个常见且需要妥善处理的问题。跨域(Cross-Origin)主要指的是在浏览器中,当前网页的域名、协议、端口与请求资源的域名、协议、端口不一致时,就发生了跨域。由于浏览器出于安全考虑,限制了不同域之间的资源访问,这主要是为了防止恶意网站利用用户的身份进行一些危险的操作,从而保护用户的隐私和安全。

一、同源策略简介

1.1、什么是源

在Web安全上下文中,源(Origin)是指一个URL的协议、域名和端口号的组合。这三个部分共同定义了资源的来源,浏览器会根据这些信息来判断两个资源是否属于同一源。例如,https://www.example.com:443http://www.example.com虽然域名相同,但由于协议和端口号不同,它们被视为不同的源。

1.2、什么是同源

同源(Same-Origin)是指两个URL的协议、域名和端口号完全相同。只有当这些条件都满足时,浏览器才认为这两个资源来自同一源,从而允许它们之间的交互操作。同源策略是浏览器安全策略的一部分,用于限制不同源之间的资源访问,以防止恶意网站窃取或篡改用户数据。

1.3、是否是同源的判断

判断两个URL是否同源,需要比较它们的协议、域名和端口号是否完全相同。以下是一些示例:

1.4、哪些操作不受同源策略限制

尽管同源策略严格限制了跨源的资源访问,但以下操作通常不受其限制:

  1. 页面中的链接:用户点击链接跳转到其他网站时,不受同源策略限制。
  2. 重定向:页面重定向到另一个URL时,也不受同源策略限制。
  3. 表单提交:表单数据可以提交到与当前页面不同源的服务器。
  4. 跨域资源的嵌入:如<script src="...">、<img>、<link>、<iframe>等标签可以嵌入来自不同源的资源,但脚本不能通过DOM API访问这些资源的内容。

1.5、跨域的概念

跨域(Cross-Origin)是指浏览器尝试访问或操作与当前页面不同源的资源。由于同源策略的限制,跨域请求通常会被浏览器阻止,除非服务器明确允许(如通过CORS头部)。跨域问题在Web开发中非常常见,特别是在需要调用第三方API或在不同子域之间共享资源时。

1.6、跨域解决方案

为了解决跨域问题,可以采取以下几种方法:

  1. JSONP:一种利用<script>标签不受同源策略限制的特性实现的跨域数据交换方式。但JSONP只支持GET请求,且存在安全风险。
  2. CORS(Cross-Origin Resource Sharing):现代浏览器支持的跨域资源共享标准。通过服务器设置特定的HTTP响应头(如Access-Control-Allow-Origin)来允许或拒绝跨域请求。CORS是目前最常用且最安全的跨域解决方案。
  3. 代理服务器:将跨域请求转发到同源的代理服务器上,再由代理服务器向目标服务器发起请求,最后将响应返回给客户端。这种方法可以绕过浏览器的同源策略限制,但需要在服务器端进行额外的配置。
  4. 降域:通过修改document.domain属性(仅适用于子域之间的跨域),使不同子域的页面能够相互访问。但这种方法存在安全风险,且应用场景有限。
  5. 其他技术:如window.postMessage、WebSocket等也可以用于实现跨域通信,但它们的使用场景和限制条件各不相同。

二、CORS 简介

CORS(Cross-Origin Resource Sharing,跨源资源共享)是由W3C提出的一种机制,旨在解决浏览器同源策略(Same-Origin Policy)的限制,允许网页从不同的源(协议+域名+端口)加载资源。CORS通过服务器设置特定的HTTP头部信息,来告诉浏览器哪些跨域请求是被允许的,从而实现了安全的跨域通信。

2.1、CORS 的核心思想

  • 不破坏既有规则:CORS在保持浏览器同源策略的基础上,提供了一种机制来允许跨域请求。
  • 服务器控制:CORS的实现完全依赖于服务器端的配置,服务器通过发送特定的HTTP头部来告知浏览器哪些跨域请求是被允许的。

2.2、CORS 请求分类

CORS将跨域请求分为两类:简单请求(Simple Requests)和非简单请求(Preflighted Requests)。

1. 简单请求

简单请求是指那些满足以下条件的HTTP请求:

  • 请求方法只能是GET、HEAD或POST。
  • 对于POST方法,Content-Type的值只能是application/x-www-form-urlencoded、multipart/form-data或text/plain。
  • 请求中的HTTP头信息不能包含除上述简单请求允许字段外的其他自定义字段。

简单请求在发送时,浏览器会自动在请求头中添加Origin字段,表明请求的来源。服务器根据Origin字段的值判断是否允许该跨域请求。如果允许,服务器会在响应头中添加Access-Control-Allow-Origin字段,并可能包含其他CORS相关的字段,如Access-Control-Allow-Credentials、Access-Control-Expose-Headers等。

2. 非简单请求

对于不满足简单请求条件的跨域请求,浏览器会先发送一个OPTIONS请求作为预检请求(Preflight Request),以询问服务器是否允许该跨域请求。预检请求会包含以下CORS相关的HTTP头信息:

  • Origin:表明请求的来源。
  • Access-Control-Request-Method:实际请求将使用的HTTP方法。
  • Access-Control-Request-Headers:实际请求将携带的自定义HTTP头信息字段。

服务器收到预检请求后,会检查Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段,以决定是否允许该跨域请求。如果允许,服务器会在响应头中添加以下CORS相关的字段:

  • Access-Control-Allow-Origin:表明允许哪个源的请求。
  • Access-Control-Allow-Methods:表明允许哪些HTTP方法。
  • Access-Control-Allow-Headers:表明允许哪些自定义HTTP头信息字段。
  • Access-Control-Allow-Credentials:表明是否允许发送Cookie。
  • Access-Control-Max-Age:表明预检请求的有效期(单位为秒),在有效期内,浏览器不会重复发送预检请求。

当预检请求通过后,浏览器才会发送实际的跨域请求。

三、SpringBoot配置Cors解决跨域问题

在Spring Boot中处理跨域资源共享(CORS)问题,可以通过几种方式来实现。这里主要介绍两种常见的方法:使用@CrossOrigin注解和配置全局CORS。

1. 使用@CrossOrigin注解

在Spring Boot中@CrossOrigin注解是一个非常有用的工具,用于处理跨域资源共享(CORS)问题。这个注解可以被放置在类级别或方法级别,以控制哪些跨域请求被允许。它提供了灵活的CORS支持,允许你指定哪些源(origins)、HTTP方法、头部(headers)和是否允许发送Cookie等。

下面我将详细解释@CrossOrigin注解及其各个属性的含义,并展示如何将它们应用于类和方法。

属性说明

  • origins:允许访问该资源的源列表。可以使用通配符*来允许所有源,或者使用具体的URL列表。
  • methods:允许的HTTP方法列表,如GET、POST、PUT、DELETE等。默认允许所有方法。
  • allowedHeaders:允许的HTTP头部列表。可以使用*来允许所有头部。
  • exposedHeaders:浏览器可以访问的响应头部列表。这些头部通常由后端设置,但浏览器出于安全考虑可能默认不暴露给前端。
  • allowCredentials:是否允许发送Cookie。默认情况下,CORS请求不会发送Cookie。当设置为true时,允许发送Cookie,但此时origins不能设置为*,必须明确指定具体的源。
  • maxAge:预检请求(preflight request)的缓存时间,单位为秒。预检请求是浏览器在发送实际请求之前发送的一种请求,用于检查服务器是否允许跨域请求。设置这个值可以减少预检请求的频率,提高性能。

类级别使用

当@CrossOrigin注解被放置在类上时,它会影响该类中所有方法的CORS设置。

@RestController  
@CrossOrigin(origins = "http://example.com", maxAge = 3600)  
public class MyController {  
  
    @GetMapping("/greeting")  
    public String greeting() {  
        return "Hello, World!";  
    }  
  
    // 这个方法也会继承类级别的CORS设置  
    @PostMapping("/postGreeting")  
    public String postGreeting() {  
        return "Hello, POST World!";  
    }  
}

image.gif

方法级别使用

@RestController  
public class MyController {  
  
    @CrossOrigin(origins = "http://specific.com", allowCredentials = "true")  
    @GetMapping("/secureGreeting")  
    public String secureGreeting() {  
        return "Secure Hello, World!";  
    }  
  
    // 这个方法不会继承任何CORS设置,因为它没有@CrossOrigin注解  
    @GetMapping("/noCorsGreeting")  
    public String noCorsGreeting() {  
        return "Hello, No CORS!";  
    }  
}

image.gif

你也可以在方法级别使用@CrossOrigin注解,以覆盖类级别的设置或仅为该方法提供CORS支持。

在上面的例子中,secureGreeting方法通过@CrossOrigin注解明确指定了允许来自http://specific.com的跨域请求,并允许发送Cookie。而noCorsGreeting方法则没有CORS支持,因此它不能响应来自不同源的跨域请求。

通过这种方式,你可以非常灵活地控制你的Spring Boot应用的CORS策略,以满足不同的安全和性能需求。

2. 配置全局CORS

如果你希望为你的整个应用设置统一的CORS策略,而不是在每个控制器或方法上单独设置,那么全局CORS配置是一个更好的选择。Spring Boot允许你通过添加一个CORS配置类来实现这一点。

方式一:通过CorsFilterBean配置CORS

步骤细节

  1. 定义CORS配置
    首先,我们定义一个私有方法(如buildConfig),用于构建并返回一个CorsConfiguration对象。在这个对象中,我们设置了允许的源(allowedOrigins)、允许的HTTP方法(allowedMethods)、允许的头部(allowedHeaders)以及是否允许发送Cookie(setAllowCredentials)。
  2. 注册CORS配置
    接着,我们创建一个CorsFilter的Bean(如corsFilter方法)。在这个方法中,我们首先创建一个UrlBasedCorsConfigurationSource对象,这个对象用于将特定的CORS配置与特定的URL模式关联起来。然后,我们使用registerCorsConfiguration方法将之前构建的CORS配置应用到所有URL模式(/**)上。
  3. 整合到Spring Boot应用:
    最后,由于CorsFilter的Bean是在一个带有@Configuration注解的类中定义的,因此Spring Boot会自动检测到它,并将其注册到应用的上下文中。这样,每当有HTTP请求到达时,CorsFilter就会根据配置的CORS策略来检查并处理这些请求。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); // 允许任何域名使用
        corsConfiguration.addAllowedHeader("*"); // 允许任何头
        corsConfiguration.addAllowedMethod("*"); // 允许任何方法(post、get等)
        corsConfiguration.setAllowCredentials(true);
        return corsConfiguration;
    }
    
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig()); // 对接口配置跨域设置
        return new CorsFilter(source);
    }
}

image.gif

方式二:通过实现WebMvcConfigurer接口配置CORS

我们通过实现WebMvcConfigurer接口并重写addCorsMappings方法来配置CORS。这种方式利用了Spring MVC的自动配置机制,使得CORS配置更加简洁和直观。

步骤细节:

  1. 实现WebMvcConfigurer接口:
    首先,我们创建一个配置类(如GlobalCorsConfig),并让它实现WebMvcConfigurer接口。
  2. 重写addCorsMappings方法:
    然后,我们在这个配置类中重写addCorsMappings方法。在这个方法中,我们使用CorsRegistry对象来定义CORS策略。我们通过调用addMapping方法来指定哪些URL模式应该应用这些策略,并通过链式调用allowedOrigins、allowedMethods、allowedHeaders、allowCredentials和maxAge等方法来设置具体的CORS规则。
  3. 整合到Spring Boot应用:
    由于这个配置类被@Configuration注解标记,Spring Boot会自动检测到它,并在启动时调用addCorsMappings方法来配置CORS。
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration //加配置注解可以扫描到
public class WebConfig implements WebMvcConfigurer{
    
    //跨域请求配置
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        WebMvcConfigurer.super.addCorsMappings(registry);
        registry.addMapping("/**")// 对接口配置跨域设置
                .allowedHeaders("*")// 允许任何头
                .allowedMethods("POST","GET")// 允许方法(post、get等)
                .allowedOrigins("*")// 允许任何域名使用
                .allowCredentials(true);
    }
    
}

image.gif

总结

  • 使用@CrossOrigin注解可以快速地为单个控制器或方法启用CORS,适用于简单的CORS需求。
  • 全局CORS配置,例如通过实现WebMvcConfigurer接口并重写addCorsMappings方法来实现,适用于需要为整个应用设置统一CORS策略的场景。这种方式更加灵活,能够更好地满足复杂的CORS需求。
相关文章
|
6天前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
21 4
|
8天前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
43 3
|
9天前
|
JavaScript 前端开发 Java
解决跨域问题大集合:vue-cli项目 和 java/springboot(6种方式) 两端解决(完美解决)
这篇文章详细介绍了如何在前端Vue项目和后端Spring Boot项目中通过多种方式解决跨域问题。
175 1
解决跨域问题大集合:vue-cli项目 和 java/springboot(6种方式) 两端解决(完美解决)
|
1天前
|
安全 Java 数据安全/隐私保护
如何配置 Java 安全管理器来避免访问控制异常
配置Java安全管理器以防止访问控制异常,需在启动JVM时通过 `-Djava.security.manager` 参数启用,并设置安全策略文件,定义权限规则,限制代码执行操作,确保应用安全。
|
4天前
|
JavaScript Java 关系型数据库
自主版权的Java诊所管理系统源码,采用Vue 2、Spring Boot等技术栈,支持二次开发
这是一个自主版权的Java诊所管理系统源码,支持二次开发。采用Vue 2、Spring Boot等技术栈,涵盖患者管理、医生管理、门诊管理、药店管理、药品管理、收费管理、医保管理、报表统计及病历电子化等功能模块。
|
4天前
|
Java BI 调度
Java Spring的定时任务的配置和使用
遵循上述步骤,你就可以在Spring应用中轻松地配置和使用定时任务,满足各种定时处理需求。
20 1
|
10天前
|
缓存 前端开发 应用服务中间件
CORS跨域+Nginx配置、Apache配置
CORS跨域+Nginx配置、Apache配置
46 7
|
8天前
|
前端开发 JavaScript UED
构建现代Web应用:使用React框架打造单页面应用
【10月更文挑战第9天】构建现代Web应用:使用React框架打造单页面应用
|
8天前
|
前端开发 JavaScript 开发者
探索现代Web前端技术:React框架入门
【10月更文挑战第9天】 探索现代Web前端技术:React框架入门
|
11天前
|
NoSQL Java 数据库连接
springBoot:整合其他框架&condition&切换web配置 (五)
本文档介绍了如何在Spring Boot项目中整合JUnit、Redis和MyBatis等框架,并提供了相应的依赖配置示例。同时,还展示了如何通过条件注解实现Bean的条件创建,以及如何切换Web服务器配置,从默认的Tomcat切换到Jetty。