SpringBoot 配置CORS处理前后端分离跨域配置无效问题解析

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: SpringBoot 配置CORS处理前后端分离跨域配置无效问题解析

前言

浏览器有跨域限制,非同源策略(协议、主机名或端口不同)被视为跨域请求,解决跨域有跨域资源共享(CORS)、反向代理和 JSONP的方式。本篇通过 SpringBoot 的资源共享配置(CORS)来解决前后端分离项目的跨域,以及从原理上去解决跨域配置不生效的问题。


准备工作

使用前后端分离开源项目 youlai-boot + vue3-element-admin 做跨域请求测试 。


其中 vue3-element-admin 默认通过 vite + proxy 前端反向代理解决跨域,如果想关闭方向代理只需修改 baseURL 即可:


// request.ts

const service = axios.create({

 //baseURL: import.meta.env.VITE_APP_BASE_API,  // 前端反向代理解决跨域的配置

 baseURL: "http://localhost:8989", // 后端通过配置CORS解决跨域的配置, http://localhost:8989 是后端接口地址

 timeout: 50000,

 headers: { 'Content-Type': 'application/json;charset=utf-8' }

});

配置 CORS 允许跨域

一般情况在项目添加以下配置即可解决浏览器跨域限制。


/**

* CORS 资源共享配置

*

* @author haoxr

* @date 2022/10/24

*/

@Configuration

public class CorsConfig {

   @Bean

   public CorsFilter corsFilter() {

       CorsConfiguration corsConfiguration = new CorsConfiguration();

       //1.允许任何来源

       corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*"));

       //2.允许任何请求头

       corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);

       //3.允许任何方法

       corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);

       //4.允许凭证

       corsConfiguration.setAllowCredentials(true);

       UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

       source.registerCorsConfiguration("/**", corsConfiguration);

       return new CorsFilter(source);

   }

}


CORS 允许跨域原理

CorsFilter 读取 CorsConfig 配置通过 DefaultCorsProcessor 给 response 响应头添加 Access-Control-Allow-* 以允许跨域请求能够被成功处理。


响应头参数 作用

Access-Control-Allow-Origin 允许访问的源地址

Access-Control-Allow-Methods 允许访问的请求方法

Access-Control-Allow-Headers 允许访问的请求头

Access-Control-Allow-Credentials 是否允许发送 Cookie 等身份凭证

Access-Control-Max-Age 缓存预检请求的时间

核心是 DefaultCorsProcessor# handleInternal 方法

微信图片_20230710102901.png

微信图片_20230710102949.png




CORS 配置失效原理分析

但。。。有的项目按照如上配置允许跨域请求成功了,但有些项目却不生效?


其实就是一个**结论**:有中断响应的过滤器在 CorsFilter 之前执行了,也就无法执行到 CorsFilter,自然 CorsConfiguration 中的配置形同虚设。


常见的场景:项目中使用了 Spring Security 安全框架导致 CORS 跨域配置失效。


接下来就 Spring Security 导致 CORS 配置失效展开分析。


在 ApplicationFilterChain#internalDoFilter 添加断点,然后通过改造后(移除反向代理)的 vue3-element-admin 发出跨域请求。

微信图片_20230710103029.png



可以看出 SpringSecurityFilterChain 是先于 CorsFilter 执行的(重点), 如果是跨域请求浏览器会在正式请求前发出一次预检请求(OPTIONS),判断服务器是否允许跨域。


跨域请求没到达 CorsFilter 过滤器就先被 Spring Security 的过滤器给拦截了,要知道预检 OPTIONS 请求是不带 token 的,所以响应 401 未认证的错误。预检请求失败导致后面的请求响应会被浏览器拦截。

微信图片_20230710103044.png



CORS 配置失效解决方案

根据配置失效原理分析,有两个解决方案:


解决方案一: 配置 CorsFilter 优先于 SpringSecurityFilter 执行;


解决方案二: 放行预检 OPTIONS 请求 + 基础 CORS 配置。


解决方案一(推荐)

配置 CorsFilter 优先于 SpringSecurityFilter 执行


Spring Security 过滤器是通过 SecurityFilterAutoConfiguration 的 DelegatingFilterProxyRegistrationBean 注册到 servletContext上下文,其中过滤器的顺序属性 Order 读取的 是 SecurityProperties 的默认配置也就是 -100;

微信图片_20230710103053.png微信图片_20230710103055.png


SpringBoot 可以通过 FilterRegistrationBean 来对 Filter 自定义注册(排序), 设置 Order 小于 SpringSecurity 的 -100 即可。完整配置如下:


/**

* CORS资源共享配置

*

* @author haoxr

* @date 2023/4/17

*/

@Configuration

public class CorsConfig {

   @Bean

   public FilterRegistrationBean filterRegistrationBean() {

       CorsConfiguration corsConfiguration = new CorsConfiguration();

       //1.允许任何来源

       corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*"));

       //2.允许任何请求头

       corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);

       //3.允许任何方法

       corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);

       //4.允许凭证

       corsConfiguration.setAllowCredentials(true);

       UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

       source.registerCorsConfiguration("/**", corsConfiguration);

       CorsFilter corsFilter = new CorsFilter(source);

       FilterRegistrationBean<CorsFilter> filterRegistrationBean=new FilterRegistrationBean<>(corsFilter);

       filterRegistrationBean.setOrder(-101);  // 小于 SpringSecurity Filter的 Order(-100) 即可

       return filterRegistrationBean;

   }

}


可以看到不同源的跨域请求能够成功响应。

微信图片_20230710103111.png



解决方案二

放行预检 OPTIONS 请求 + 基础 CORS 配置


SecurityConfig 放行 OPTIONS 预检请求配置 SecurityConfig 配置源码


   @Bean

   public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

       http

            ...

               // 走 Spring Security 过滤器链的放行配置

               .requestMatchers(HttpMethod.OPTIONS,"/**").permitAll() // 放行预检请求

               .anyRequest().authenticated();

       return http.build();

   }

   @Bean

   public WebSecurityCustomizer webSecurityCustomizer() {

       // 不走过滤器链的放行配置

       return (web) -> web.ignoring()

               .requestMatchers(HttpMethod.OPTIONS,"/**") // 放行预检请求

     

   }


基础的跨域共享配置


@Configuration

public class CorsConfig {

   @Bean

   public CorsFilter corsFilter() {

       CorsConfiguration corsConfiguration = new CorsConfiguration();

       //1.允许任何来源

       corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*"));

       //2.允许任何请求头

       corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);

       //3.允许任何方法

       corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);

       //4.允许凭证

       corsConfiguration.setAllowCredentials(true);

       UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

       source.registerCorsConfiguration("/**", corsConfiguration);

       return new CorsFilter(source);

   }

 

}


另外有自定义过滤器 (例如:VerifyCodeFilter)通过 response.getWriter().print() 响应给浏览器也是不走后面的 CorsFilter 过滤器,所以需要设置响应头


// ResponseUtils# writeErrMsg

response.setContentType(MediaType.APPLICATION_JSON_VALUE);

response.setHeader("Access-Control-Allow-Origin","*");

response.getWriter().print(JSONUtil.toJsonStr(Result.failed(resultCode)));

1

2

3

4

前/后端源码

完整项目源码地址如下,如果有相关问题可以通过项目 关于我们 添加交流群。


Gitee Github

前端 vue3-element-admin vue3-element-admin

后端 youlai-boot youlai-boot


相关文章
|
12天前
|
前端开发 数据可视化 Java
SpringBoot的4中常见入参形式错误解析
在使用SpringBoot进行前后端接口对接时,常遇到如500、400等请求错误,本文总结了四个常见的复杂请求类型及其解决方案,包括实体嵌套List提交、普通文件上传、List提交及数组Array提交,详细展示了正确的前端与后端代码实现,帮助开发者避免常见错误,提高开发效率。
22 0
SpringBoot的4中常见入参形式错误解析
|
10天前
|
IDE Java 开发工具
还在为繁琐的配置头疼吗?一文教你如何用 Spring Boot 快速启动,让开发效率飙升,从此告别加班——打造你的首个轻量级应用!
【9月更文挑战第2天】Spring Boot 是一款基于 Spring 框架的简化开发工具包,采用“约定优于配置”的原则,帮助开发者快速创建独立的生产级应用程序。本文将指导您完成首个 Spring Boot 项目的搭建过程,包括环境配置、项目初始化、添加依赖、编写控制器及运行应用。首先需确保 JDK 版本不低于 8,并安装支持 Spring Boot 的现代 IDE,如 IntelliJ IDEA 或 Eclipse。
39 5
|
11天前
|
持续交付 jenkins Devops
WPF与DevOps的完美邂逅:从Jenkins配置到自动化部署,全流程解析持续集成与持续交付的最佳实践
【8月更文挑战第31天】WPF与DevOps的结合开启了软件生命周期管理的新篇章。通过Jenkins等CI/CD工具,实现从代码提交到自动构建、测试及部署的全流程自动化。本文详细介绍了如何配置Jenkins来管理WPF项目的构建任务,确保每次代码提交都能触发自动化流程,提升开发效率和代码质量。这一方法不仅简化了开发流程,还加强了团队协作,是WPF开发者拥抱DevOps文化的理想指南。
31 1
|
14天前
|
Java 微服务 Spring
Spring Cloud全解析:配置中心之解决configserver单点问题
但是如果该configserver挂掉了,那就无法获取最新的配置了,微服务就出现了configserver的单点问题,那么如何避免configserver单点呢?
|
11天前
|
持续交付 jenkins C#
“WPF与DevOps深度融合:从Jenkins配置到自动化部署全流程解析,助你实现持续集成与持续交付的无缝衔接”
【8月更文挑战第31天】本文详细介绍如何在Windows Presentation Foundation(WPF)项目中应用DevOps实践,实现自动化部署与持续集成。通过具体代码示例和步骤指导,介绍选择Jenkins作为CI/CD工具,结合Git进行源码管理,配置构建任务、触发器、环境、构建步骤、测试及部署等环节,显著提升开发效率和代码质量。
30 0
|
11天前
|
Java Spring 开发者
解锁 Spring Boot 自动化配置的黑科技:带你走进一键配置的高效开发新时代,再也不怕繁琐设置!
【8月更文挑战第31天】Spring Boot 的自动化配置机制极大简化了开发流程,使开发者能专注业务逻辑。通过 `@SpringBootApplication` 注解组合,特别是 `@EnableAutoConfiguration`,Spring Boot 可自动激活所需配置。例如,添加 JPA 依赖后,只需在 `application.properties` 配置数据库信息,即可自动完成 JPA 和数据源设置。这一机制基于多种条件注解(如 `@ConditionalOnClass`)实现智能配置。深入理解该机制有助于提升开发效率并更好地解决问题。
23 0
|
14天前
|
缓存 Java 数据库连接
Spring Boot 资源文件属性配置,紧跟技术热点,为你的应用注入灵动活力!
【8月更文挑战第29天】在Spring Boot开发中,资源文件属性配置至关重要,它让开发者能灵活定制应用行为而不改动代码,极大提升了可维护性和扩展性。Spring Boot支持多种配置文件类型,如`application.properties`和`application.yml`,分别位于项目的resources目录下。`.properties`文件采用键值对形式,而`yml`文件则具有更清晰的层次结构,适合复杂配置。此外,Spring Boot还支持占位符引用和其他外部来源的属性值,便于不同环境下覆盖默认配置。通过合理配置,应用能快速适应各种环境与需求变化。
26 0
|
14天前
|
机器学习/深度学习 计算机视觉 Python
深度学习项目中在yaml文件中定义配置,以及使用的python的PyYAML库包读取解析yaml配置文件
深度学习项目中在yaml文件中定义配置,以及使用的python的PyYAML库包读取解析yaml配置文件
28 0
|
17天前
|
XML Java 应用服务中间件
SpringBoot启动流程解析
SpringBoot启动流程解析
24 0
|
18天前
|
安全 数据安全/隐私保护

推荐镜像

更多