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

已配置白名单端口仍遭CORS拦截?Spring Boot跨域问题求助

问题

前端运行在4200端口,调用Spring Boot 3.1后端的http://localhost:8080/writer/create接口时,收到CORS拦截错误:

Access to fetch at 'http://localhost:8080/writer/create' from origin 'http://localhost:4200' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

已在后端配置SecurityConfig类(包含CorsFilter,将http://localhost:4200加入允许源白名单),代码如下:

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final JwtAuthenticationFilter jwtAuthFilter;
    private final AuthenticationProvider authenticationProvider;


    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
            http
                    .csrf(csrf -> csrf.disable())
                    .authorizeRequests()
                    .requestMatchers("api/v1/auth/**","reader/**")
                    .permitAll()
                    .requestMatchers("/writer/**").hasAnyAuthority("WRITER")
                    .anyRequest()
                    .authenticated()
                    .and()
                    .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                    .authenticationProvider(authenticationProvider)
                    .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
        return  http.build();
    }


    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setAllowedOrigins(Collections.singletonList("http://localhost:4200"));
        corsConfiguration.setAllowedHeaders(Arrays.asList("Origin", "Access-Control-Allow-Origin", "Content-Type",
                "Accept", "Authorization", "Origin, Accept", "X-Requested-With",
                "Access-Control-Request-Method", "Access-Control-Request-Headers"));
        corsConfiguration.setExposedHeaders(Arrays.asList("Origin", "Content-Type", "Accept", "Authorization",
                "Access-Control-Allow-Origin", "Access-Control-Allow-Origin", "Access-Control-Allow-Credentials"));
        corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new   UrlBasedCorsConfigurationSource();
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);

        return new CorsFilter(urlBasedCorsConfigurationSource);
    }

}

为何4200端口仍被拦截?如何实现前后端正常调用?

原因分析

问题核心是过滤器执行顺序冲突:自定义的CorsFilter默认在Spring Security过滤器链之后执行,而/writer/**接口需要WRITER权限,OPTIONS预检请求未携带JWT令牌,会被Security的权限校验直接拦截,根本没机会走到CorsFilter处理,导致响应头缺失Access-Control-Allow-Origin。

另外,Spring Boot 3.x官方推荐直接通过HttpSecurity集成CORS配置,而非单独注册CorsFilter,这样能确保CORS逻辑在权限校验前执行。

解决方案

修改SecurityConfig,将CORS配置直接集成到Security过滤器链中,替换原有独立的CorsFilter Bean:

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final JwtAuthenticationFilter jwtAuthFilter;
    private final AuthenticationProvider authenticationProvider;


    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
            http
                    .csrf(csrf -> csrf.disable())
                    // 集成CORS配置到Security链
                    .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                    .authorizeRequests()
                    .requestMatchers("api/v1/auth/**","reader/**")
                    .permitAll()
                    // 允许所有OPTIONS预检请求直接通过,无需权限校验
                    .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                    .requestMatchers("/writer/**").hasAnyAuthority("WRITER")
                    .anyRequest()
                    .authenticated()
                    .and()
                    .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                    .authenticationProvider(authenticationProvider)
                    .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
        return  http.build();
    }

    // 定义CORS配置源
    private CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setAllowedOrigins(Collections.singletonList("http://localhost:4200"));
        // 清理冗余的响应头配置,只保留请求允许的头
        corsConfiguration.setAllowedHeaders(Arrays.asList("Origin", "Content-Type",
                "Accept", "Authorization", "X-Requested-With",
                "Access-Control-Request-Method", "Access-Control-Request-Headers"));
        corsConfiguration.setExposedHeaders(Arrays.asList("Origin", "Content-Type", "Accept", "Authorization",
                "Access-Control-Allow-Credentials"));
        corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return source;
    }

}

关键修改说明

  1. 通过http.cors()将CORS逻辑嵌入Security过滤器链,确保CORS处理在权限校验之前完成
  2. 添加requestMatchers(HttpMethod.OPTIONS, "/**").permitAll(),放行所有OPTIONS预检请求,避免无令牌被拦截
  3. 清理了AllowedHeaders中重复的Access-Control-Allow-Origin(该字段是响应头,无需配置在请求允许头列表)

额外检查项

  • 若前端需要传递Cookie或认证信息,确保请求携带withCredentials: true参数
  • 重启后端服务,确保配置生效

内容的提问来源于stack exchange,提问作者Tanabata Cinco

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 13:46:09