欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > Spring Boot + Vue 跨域配置(CORS)问题解决历程

Spring Boot + Vue 跨域配置(CORS)问题解决历程

2025/2/23 1:05:57 来源:https://blog.csdn.net/qq_21484461/article/details/139707263  浏览:    关键词:Spring Boot + Vue 跨域配置(CORS)问题解决历程

在使用 Spring Boot 和 Vue 开发前后端分离的项目时,跨域资源共享(CORS)问题是一个常见的挑战。接下来,我将分享我是如何一步步解决这个问题的,包括中间的一些试错过程,希望能够帮助到正在经历类似问题的你。

1. 问题描述

在我们开发的过程中,Vue 前端需要与 Spring Boot 后端通信。如果后端没有正确配置 CORS,浏览器会进行跨域检查并阻止请求,报错信息如下:

Access to XMLHttpRequest at 'http://localhost:8789/auth/register' from origin 'http://localhost:8081' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

2. 解决方案概述

为了解决这个问题,我们需要在 Spring Boot 应用中配置 CORS。这个过程包括创建一个 CORS 配置类,并在 Spring Security 配置类中应用这个配置。

3. 试错过程

3.1 初步尝试:简单的 CORS 配置

我首先尝试在 Spring Boot 中添加一个简单的 CORS 配置类:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;@Configuration
public class CorsConfig {@Beanpublic CorsConfigurationSource corsConfigurationSource() {CorsConfiguration configuration = new CorsConfiguration();configuration.addAllowedOrigin("*");configuration.addAllowedMethod("*");configuration.addAllowedHeader("*");configuration.setAllowCredentials(true);configuration.setMaxAge(3600L);UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", configuration);return source;}
}

然后,在 WebSecurityConfig 中应用这个配置:

http.cors().configurationSource(corsConfigurationSource());

结果,前端依旧报错,没有任何变化。

3.2 细化 Security 配置

我接着尝试在 WebSecurityConfig 中进一步细化 CORS 配置:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.cors().configurationSource(corsConfigurationSource()).and().csrf().disable();}@BeanCorsConfigurationSource corsConfigurationSource() {CorsConfiguration configuration = new CorsConfiguration();configuration.addAllowedOrigin("*");configuration.addAllowedMethod("*");configuration.addAllowedHeader("*");configuration.setAllowCredentials(true);configuration.setMaxAge(3600L);UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", configuration);return source;}
}

然而,前端还是无法正常发起跨域请求,这让我非常困惑。

3.3 尝试代理配置

为了确保开发过程中跨域请求能正确代理到后端,我在 Vue 项目中添加了代理配置:

首先,确保项目使用 vue-cli 创建,并确保有 vue.config.js 文件。然后添加如下代理配置:

let proxyObj = {};
proxyObj['/'] = {target: 'http://localhost:8789/',changeOrigin: true,pathRewrite: {'^/': ''}
}module.exports = {devServer: {open: true,host: 'localhost',port: 8081,proxy: proxyObj,},
}

这种配置可以使前端的跨域请求通过代理转发到后端。不过,这只是开发环境下的解决方案,并没有真正解决后端的 CORS 配置问题。

3.4 最终解决方案:完善的 CORS 和 Security 配置

经过几次尝试和查阅资料后,我最终找到了一个有效的解决方案,结合之前的经验,创建了一个完善的 CORS 和 Security 配置。

CorsConfig.java
package cn.techfanyi.fanyi.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;@Configuration
public class CorsConfig {@Beanpublic CorsConfigurationSource corsConfigurationSource() {CorsConfiguration corsConfig = new CorsConfiguration();corsConfig.addAllowedOriginPattern("*"); // 允许任何源corsConfig.addAllowedMethod("*"); // 允许任何HTTP方法corsConfig.addAllowedHeader("*"); // 允许任何HTTP头corsConfig.setAllowCredentials(true); // 允许证书(cookies)corsConfig.setMaxAge(3600L); // 预检请求的缓存时间(秒)UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", corsConfig); // 对所有路径应用这个配置return source;}
}
WebSecurityConfig.java
package cn.techfanyi.fanyi.config;import cn.techfanyi.fanyi.filter.JwtRequestFilter;
import cn.techfanyi.fanyi.security.CustomAccessDeniedHandler;
import cn.techfanyi.fanyi.security.CustomAuthenticationEntryPoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {private final JwtRequestFilter jwtRequestFilter;private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;private final CustomAccessDeniedHandler customAccessDeniedHandler;public WebSecurityConfig(JwtRequestFilter jwtRequestFilter,CustomAuthenticationEntryPoint customAuthenticationEntryPoint,CustomAccessDeniedHandler customAccessDeniedHandler) {this.jwtRequestFilter = jwtRequestFilter;this.customAuthenticationEntryPoint = customAuthenticationEntryPoint;this.customAccessDeniedHandler = customAccessDeniedHandler;}@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws  Exception {http.csrf().disable().cors(cors -> cors.configurationSource(corsConfigurationSource())).authorizeRequests(authorizedRequests ->authorizedRequests.requestMatchers("/**").permitAll().anyRequest().authenticated()).exceptionHandling(exceptionHandling ->exceptionHandling.authenticationEntryPoint(customAuthenticationEntryPoint).accessDeniedHandler(customAccessDeniedHandler)).sessionManagement(sessionManagement ->sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)).addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);return http.build();}@Beanpublic BCryptPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {return authenticationConfiguration.getAuthenticationManager();}private CorsConfigurationSource corsConfigurationSource() {return new CorsConfig().corsConfigurationSource();}
}

但是又出现以下错误:

java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.

这个错误信息表明,在 Spring Boot 的 CORS 配置中,当 allowCredentials 设置为 true 时,allowedOrigins 不能包含特殊值 "*", 因为浏览器不允许在 Access-Control-Allow-Origin 响应头中设置 "*", 同时还允许凭证(如 cookies)。此时应该使用 allowedOriginPatterns 来代替 allowedOrigins

具体的错误原因如下:

java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.

这意味着当 allowCredentials 设置为 true 时,不能将 allowedOrigins 设置为 "*", 因为它不能在响应头中设置 Access-Control-Allow-Origin"*", 同时还允许凭证。为了解决这个问题,您需要将 allowedOrigins 改为使用 allowedOriginPatterns

修改 CorsConfigurationSource 如下:

 @Beanpublic CorsConfigurationSource corsConfigurationSource() {CorsConfiguration corsConfig = new CorsConfiguration();corsConfig.addAllowedOriginPattern("*"); // 使用 allowedOriginPatterns 代替 allowedOriginscorsConfig.addAllowedMethod("*"); corsConfig.addAllowedHeader("*");corsConfig.setAllowCredentials(true);corsConfig.setMaxAge(3600L);UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", corsConfig);return source;}

通过以上配置,可以解决 allowCredentialsallowedOrigins"*" 冲突的问题,使得您的 Spring Boot 应用可以正确处理跨域请求。

通过以上配置,前端请求终于可以成功与后端通信,CORS 问题不再出现。

4. 为什么要这样修改

在 Spring Security 6 中,安全配置的方式有所变化。与之前版本相比,Spring Security 6 更加灵活和模块化。为了使 CORS 配置生效,我们需要:

  1. 明确指定 CORS 配置源:在 securityFilterChain 方法中,通过 http.cors(cors -> cors.configurationSource(corsConfigurationSource())) 明确指定使用我们自定义的 CorsConfigurationSource
  2. 禁用默认的 CSRF 保护:对于大多数 API 项目,特别是无状态的 RESTful 服务,禁用 CSRF 是常见的做法。通过 http.csrf().disable() 来实现。
  3. 配置异常处理和会话管理:确保我们的应用是无状态的,并且正确处理认证和授权异常。

5. 结果

经过这些配置,前端可以顺利地与后端通信,避免了 CORS 错误。整个过程让我对 CORS 配置有了更深入的理解。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词