You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 20:47:03