Spring Boot与Vue跨域请求遇403禁止及CORS政策错误求助
我是Spring Boot和VueJS新手,正在开发一个基于Vue前端、Spring Boot后端并通过Google SDK实现Google登录的Web应用。前端和后端单独运行正常,但两者间通信失败。当我通过BackendService.js向后端发起GET请求时,浏览器控制台出现以下错误:
Access to XMLHttpRequest at 'BACKEND_URL/match/231' from origin 'FRONTEND_URL' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
GET BACKEND_URL/match/231 net::ERR_FAILED 403 (Forbidden)
Uncaught (in promise) AxiosError {message: 'Network Error', name: 'AxiosError', code: 'ERR_NETWORK', config: {…}, request: XMLHttpRequest, …}
现有代码
Spring SecurityConfig.java
@Configuration @EnableWebSecurity public class SecurityConfig{ @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeRequests(); CorsConfiguration cors = new CorsConfiguration(); cors.setAllowedOrigins(List.of("FRONTEND_URL")); cors.setAllowedHeaders(List.of("*")); cors.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", cors); http.authorizeRequests().anyRequest().authenticated(); http.csrf().disable(); http.cors().disable(); return http.build(); } }
pom.xml
<modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.0</version> <relativePath/> </parent> <groupId>com.example</groupId> <artifactId>MatchMaker_BE</artifactId> <version>0.0.1-SNAPSHOT</version> <name>MatchMaker_BE</name> <description>MatchMaker_BE</description> <properties> <java.version>21</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>6.2.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-oauth2-client</artifactId> <version>6.2.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Vue BackendService.js
import axios from "axios"; const BACKEND_BASE_URL = "BACKEND_URL" //const accessToken = localStorage.getItem("userInfo"); //const headers = {Authorization: "Bearer " + accessToken}; class BackendService{ getMatch(matchId){ console.log("Übermittelt match ID: " + matchId); const requestURI = BACKEND_BASE_URL + "/match/" + matchId; console.log("Übermittelt an: " + requestURI); return axios.get(requestURI/*, {headers: headers}*/); } } export default new BackendService()
尝试过的WebConfig.java
@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); // Erlaube Anfragen von allen Ursprüngen config.addAllowedOrigin("FRONTEND_URL"); // Erlaube bestimmte HTTP-Methoden (GET, POST, etc.) config.addAllowedMethod("*"); // Erlaube bestimmte HTTP-Header config.addAllowedHeader("*"); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }
我已经尝试过修改SecurityConfig的多种配置,WebSecurityConfigurerAdapter类似乎与我的Java版本不兼容。另外,我考虑过将Google SDK获取的信息作为请求头token传递给后端,但目前连后端都无法访问,不知道如何验证该token。
1. 修复跨域配置问题
你的SecurityConfig中调用了http.cors().disable();,直接禁用了CORS支持,导致之前配置的CorsConfiguration完全无效。修改SecurityConfig如下:
@Configuration @EnableWebSecurity public class SecurityConfig{ @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { // 配置CORS,使用自定义的CorsConfigurationSource http.cors(cors -> cors.configurationSource(corsConfigurationSource())) .csrf(csrf -> csrf.disable()) .authorizeRequests(auth -> auth.anyRequest().authenticated()); return http.build(); } // 单独定义CorsConfigurationSource Bean @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration cors = new CorsConfiguration(); // 替换成实际的前端URL,比如http://localhost:5173 cors.setAllowedOrigins(List.of("FRONTEND_URL")); cors.setAllowedHeaders(List.of("*")); cors.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); cors.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", cors); return source; } }
同时删除之前的WebConfig.java,避免Spring加载多个CORS配置导致冲突。
2. 处理Google登录Token验证
跨域问题解决后,可将Google SDK获取的ID Token通过请求头传递给后端,使用Spring Security OAuth2 Resource Server验证Token:
第一步:添加依赖到pom.xml
在<dependencies>中添加:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency>
第二步:修改SecurityConfig支持Token验证
更新SecurityFilterChain配置,加入OAuth2资源服务器支持:
@Configuration @EnableWebSecurity public class SecurityConfig{ @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.cors(cors -> cors.configurationSource(corsConfigurationSource())) .csrf(csrf -> csrf.disable()) .authorizeRequests(auth -> auth.anyRequest().authenticated()) // 配置OAuth2资源服务器,验证Google ID Token .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))); return http.build(); } @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration cors = new CorsConfiguration(); cors.setAllowedOrigins(List.of("FRONTEND_URL")); cors.setAllowedHeaders(List.of("*")); cors.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); cors.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", cors); return source; } // 转换Google JWT中的信息为Spring Security Authentication对象 private JwtAuthenticationConverter jwtAuthenticationConverter() { JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); grantedAuthoritiesConverter.setAuthoritiesClaimName("roles"); grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_"); JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); converter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter); return converter; } }
第三步:配置application.properties
添加Google的JWKS端点,让Spring自动验证Token:
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://www.googleapis.com/oauth2/v3/certs
第四步:前端传递Token
修改BackendService.js,将Google获取的ID Token放到请求头里:
import axios from "axios"; const BACKEND_BASE_URL = "BACKEND_URL" class BackendService{ getMatch(matchId){ console.log("Übermittelt match ID: " + matchId); const requestURI = BACKEND_BASE_URL + "/match/" + matchId; console.log("Übermittelt an: " + requestURI); // 从localStorage获取Google ID Token const idToken = localStorage.getItem("googleIdToken"); return axios.get(requestURI, { headers: { Authorization: `Bearer ${idToken}` } }); } } export default new BackendService()
3. 注意事项
- 替换代码中的
FRONTEND_URL和BACKEND_URL为实际地址,比如http://localhost:5173(Vue默认端口)和http://localhost:8080(Spring Boot默认端口)。 - 确保Google开发者控制台中已正确配置前端的授权来源,以及后端的重定向URI(若使用授权码模式)。
- 测试时可临时将
setAllowedOrigins设为List.of("*")验证跨域是否解决,之后再限制为指定的前端URL。
内容的提问来源于stack exchange,提问作者JakobScharf

