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需求。
相关文章
|
23天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
12天前
|
Java Maven Spring
Java Web 应用中,资源文件的位置和加载方式
在Java Web应用中,资源文件如配置文件、静态文件等通常放置在特定目录下,如WEB-INF或classes。通过类加载器或Servlet上下文路径可实现资源的加载与访问。正确管理资源位置与加载方式对应用的稳定性和可维护性至关重要。
|
12天前
|
开发框架 中间件 Java
如何处理跨域资源共享(CORS)的 OPTIONS 请求?
处理 CORS 的 OPTIONS 请求的关键是正确设置响应头,以告知浏览器是否允许跨域请求以及允许的具体条件。根据所使用的服务器端技术和框架,可以选择相应的方法来实现对 OPTIONS 请求的处理,从而确保跨域资源共享的正常进行。
|
12天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
25 4
|
14天前
|
缓存 监控 Java
如何运用JAVA开发API接口?
本文详细介绍了如何使用Java开发API接口,涵盖创建、实现、测试和部署接口的关键步骤。同时,讨论了接口的安全性设计和设计原则,帮助开发者构建高效、安全、易于维护的API接口。
37 4
|
12天前
|
JavaScript 前端开发 API
跨域资源共享(CORS)的工作原理是什么?
跨域资源共享(CORS)通过浏览器和服务器之间的这种交互机制,在保证安全性的前提下,实现了跨域资源的访问,使得不同源的网页能够合法地获取和共享服务器端的资源,为现代Web应用的开发提供了更大的灵活性和扩展性。
|
15天前
|
存储 安全 搜索推荐
理解Session和Cookie:Java Web开发中的用户状态管理
理解Session和Cookie:Java Web开发中的用户状态管理
40 4
|
19天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
37 2
|
18天前
|
消息中间件 NoSQL Java
springboot整合常用中间件框架案例
该项目是Spring Boot集成整合案例,涵盖多种中间件的使用示例,每个案例项目使用最小依赖,便于直接应用到自己的项目中。包括MyBatis、Redis、MongoDB、MQ、ES等的整合示例。
76 1
|
19天前
|
SQL Java 程序员
倍增 Java 程序员的开发效率
应用计算困境:Java 作为主流开发语言,在数据处理方面存在复杂度高的问题,而 SQL 虽然简洁但受限于数据库架构。SPL(Structured Process Language)是一种纯 Java 开发的数据处理语言,结合了 Java 的架构灵活性和 SQL 的简洁性。SPL 提供简洁的语法、完善的计算能力、高效的 IDE、大数据支持、与 Java 应用无缝集成以及开放性和热切换特性,能够大幅提升开发效率和性能。