SpringBoot+Vue跨域配置(CORS)問題得解決過程
1. 問題描述
在我們開發(fā)的過程中,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 應(yīng)用中配置 CORS。這個過程包括創(chuàng)建一個 CORS 配置類,并在 Spring Security 配置類中應(yīng)用這個配置。
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 { @Bean public 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
中應(yīng)用這個配置:
http.cors().configurationSource(corsConfigurationSource());
結(jié)果,前端依舊報錯,沒有任何變化。
3.2 細(xì)化 Security 配置
我接著嘗試在 WebSecurityConfig
中進一步細(xì)化 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 { @Override protected void configure(HttpSecurity http) throws Exception { http.cors().configurationSource(corsConfigurationSource()) .and().csrf().disable(); } @Bean 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; } }
然而,前端還是無法正常發(fā)起跨域請求,這讓我非常困惑。
3.3 嘗試代理配置
為了確保開發(fā)過程中跨域請求能正確代理到后端,我在 Vue 項目中添加了代理配置:
首先,確保項目使用 vue-cli
創(chuàng)建,并確保有 vue.config.js
文件。然后添加如下代理配置:
let proxyObj = {}; proxyObj['/'] = { target: 'http://localhost:8789/', changeOrigin: true, pathRewrite: { '^/': '' } } module.exports = { devServer: { open: true, host: 'localhost', port: 8081, proxy: proxyObj, }, }
這種配置可以使前端的跨域請求通過代理轉(zhuǎn)發(fā)到后端。不過,這只是開發(fā)環(huán)境下的解決方案,并沒有真正解決后端的 CORS 配置問題。
3.4 最終解決方案:完善的 CORS 和 Security 配置
經(jīng)過幾次嘗試和查閱資料后,我最終找到了一個有效的解決方案,結(jié)合之前的經(jīng)驗,創(chuàng)建了一個完善的 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 { @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration corsConfig = new CorsConfiguration(); corsConfig.addAllowedOriginPattern("*"); // 允許任何源 corsConfig.addAllowedMethod("*"); // 允許任何HTTP方法 corsConfig.addAllowedHeader("*"); // 允許任何HTTP頭 corsConfig.setAllowCredentials(true); // 允許證書(cookies) corsConfig.setMaxAge(3600L); // 預(yù)檢請求的緩存時間(秒) UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", corsConfig); // 對所有路徑應(yīng)用這個配置 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; } @Bean public 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(); } @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { return authenticationConfiguration.getAuthenticationManager(); } private CorsConfigurationSource corsConfigurationSource() { return new CorsConfig().corsConfigurationSource(); } }
但是又出現(xiàn)以下錯誤:
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 配置中,當(dāng) allowCredentials 設(shè)置為 true 時,allowedOrigins 不能包含特殊值 "*", 因為瀏覽器不允許在 Access-Control-Allow-Origin 響應(yīng)頭中設(shè)置 "*", 同時還允許憑證(如 cookies)。此時應(yīng)該使用 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.
這意味著當(dāng) allowCredentials 設(shè)置為 true 時,不能將 allowedOrigins 設(shè)置為 "*", 因為它不能在響應(yīng)頭中設(shè)置 Access-Control-Allow-Origin 為 "*", 同時還允許憑證。為了解決這個問題,您需要將 allowedOrigins 改為使用 allowedOriginPatterns。
修改 CorsConfigurationSource 如下:
@Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration corsConfig = new CorsConfiguration(); corsConfig.addAllowedOriginPattern("*"); // 使用 allowedOriginPatterns 代替 allowedOrigins corsConfig.addAllowedMethod("*"); corsConfig.addAllowedHeader("*"); corsConfig.setAllowCredentials(true); corsConfig.setMaxAge(3600L); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", corsConfig); return source; }
通過以上配置,可以解決 allowCredentials
和 allowedOrigins
中 "*"
沖突的問題,使得您的 Spring Boot 應(yīng)用可以正確處理跨域請求。
通過以上配置,前端請求終于可以成功與后端通信,CORS 問題不再出現(xiàn)。
4. 為什么要這樣修改
在 Spring Security 6 中,安全配置的方式有所變化。與之前版本相比,Spring Security 6 更加靈活和模塊化。為了使 CORS 配置生效,我們需要:
- 明確指定 CORS 配置源:在
securityFilterChain
方法中,通過http.cors(cors -> cors.configurationSource(corsConfigurationSource()))
明確指定使用我們自定義的CorsConfigurationSource
。 - 禁用默認(rèn)的 CSRF 保護:對于大多數(shù) API 項目,特別是無狀態(tài)的 RESTful 服務(wù),禁用 CSRF 是常見的做法。通過
http.csrf().disable()
來實現(xiàn)。 - 配置異常處理和會話管理:確保我們的應(yīng)用是無狀態(tài)的,并且正確處理認(rèn)證和授權(quán)異常。
5. 結(jié)果
經(jīng)過這些配置,前端可以順利地與后端通信,避免了 CORS 錯誤。整個過程讓我對 CORS 配置有了更深入的理解。
以上就是SpringBoot+Vue跨域配置(CORS)問題得解決過程的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Vue跨域配置解決的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java實現(xiàn)仿windows 字體設(shè)置選項卡實例
本篇文章介紹了java仿windows 字體設(shè)置選項卡,可實現(xiàn)類似windows字體設(shè)置效果,需要的朋友可以參考下。2016-10-10java基礎(chǔ)之TreeMap實現(xiàn)類全面詳解
這篇文章主要為大家介紹了java基礎(chǔ)之TreeMap實現(xiàn)類全面詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12SpringBoot3.2.2整合MyBatis-Plus3.5.5依賴不兼容的問題解決
這篇文章給大家介紹了Spring Boot 3.2.2整合MyBatis-Plus 3.5.5依賴不兼容問題,文中通過代碼示例和圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-01-01詳解Springboot之整合JDBCTemplate配置多數(shù)據(jù)源
這篇文章主要介紹了詳解Springboot之整合JDBCTemplate配置多數(shù)據(jù)源,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有很好的幫助,需要的朋友可以參考下2021-04-04java文字轉(zhuǎn)語音播報功能的實現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于java文字轉(zhuǎn)語音播報功能的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07Dubbo?LoadBalance基于權(quán)重的隨機負(fù)載均衡算法提高服務(wù)性能
這篇文章主要為大家介紹了Dubbo?LoadBalance基于權(quán)重的隨機負(fù)載均衡算法提高服務(wù)性能詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪<BR>2023-10-10