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

Spring Boot 2.3 OAuth集成CORS过滤器遇预检请求失败求助

Spring Boot 2.3 OAuth应用CORS预请求失败问题排查

问题现象

Postman访问应用可正常获取认证密钥,但本地HTML文件通过jQuery发起Ajax请求时触发CORS错误:

Access to XMLHttpRequest at 'my sercice' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

现有代码

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import de.mtc.procon.authserver.provider.CustomAuthenticationProvider;

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


//  @Bean
//  public CorsFilter corsFilter() {
//      return new MyCorsFilter(getMyCorsConfigurationSource());
//  }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        System.out.println("---------------------- Configure authentication server -----------------------");
        http.cors().and().authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll().antMatchers("/**").authenticated().and().httpBasic().and().csrf().disable().exceptionHandling()
            .authenticationEntryPoint(new CustomAuthenticationEntryPoint());
    }


    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);
    }

    @Qualifier
    @Primary
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        System.out.println("Generating cors configuration source...");
        return getMyCorsConfigurationSource();
    }

    private CorsConfigurationSource getMyCorsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", getMyCorsConfiguration());
        return source;
    }

    private CorsConfiguration getMyCorsConfiguration() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
        configuration.setAllowCredentials(true);
        configuration.setMaxAge(Duration.ofDays(1));
        configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
        return configuration;
    }
}

问题分析

你的包引用没有问题,使用的都是Spring官方org.springframework.web.cors下的标准类,排除包错误的可能。核心问题出在以下两点:

  1. CORS配置冲突:当设置allowCredentials=true时,allowedOrigins不能使用通配符*,这是浏览器的安全限制,会导致CORS配置不生效。
  2. 预请求被拦截:CustomAuthenticationEntryPoint可能对OPTIONS预请求返回了非200状态码,或者CORS过滤器优先级低于Spring Security,导致预请求先被Security拦截返回401。

解决方案

1. 修正CORS配置的凭证与Origin冲突

本地HTML文件的请求Origin为null,需明确允许该Origin,同时避免通配符与凭证的冲突:

private CorsConfiguration getMyCorsConfiguration() {
    CorsConfiguration configuration = new CorsConfiguration();
    // 允许本地文件的null Origin及测试用的本地服务地址
    configuration.setAllowedOrigins(Arrays.asList("null", "http://localhost:8080"));
    configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
    configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
    configuration.setAllowCredentials(true);
    configuration.setMaxAge(Duration.ofDays(1));
    configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
    return configuration;
}

2. 提升CORS过滤器优先级

注册CORS过滤器并设置最高优先级,确保它在Spring Security过滤器之前执行:

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.filter.CorsFilter;

// 新增该Bean定义
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", getMyCorsConfiguration());
    return new CorsFilter(source);
}

3. 调整认证入口点,跳过OPTIONS请求

修改CustomAuthenticationEntryPoint,不对OPTIONS预请求返回未授权:

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        // 对OPTIONS预请求直接返回200
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            // 原有认证失败处理逻辑
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
        }
    }
}

内容的提问来源于stack exchange,提问作者Felix H

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 16:18:18