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

升级Spring Boot 3后集成OKTA遇CORS错误:缺少指定响应头

Spring Boot 3升级后OAuth2授权端点CORS问题排查与解决

问题背景

我们的应用前端基于Vue.js,后端使用Spring Boot,通过OKTA实现安全认证。在Java 11 + Spring Boot 2.1.8环境下运行正常,后端REST服务地址为http://localhost:7801,前端NGINX地址为http://localhost:7800。

升级至Spring Boot 3.1.3 + Java 17后,前端访问接口时出现跨域错误:

跨域请求被阻止:同源策略不允许读取http://localhost:7801/oauth2/authorization/okta的远程资源。(原因:缺少CORS头‘Access-Control-Allow-Origin’)。状态码:403。

已完成Spring Security的适配调整,其余后端代码未修改,且OKTA中已配置http://localhost:7800和http://localhost:7800/作为可信来源。

旧版本(Spring Boot 2.1.8)配置

Security配置

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class OAuthSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .cors()
            .and().csrf().disable()
            .authorizeRequests()
            .antMatchers("/actuator/**").permitAll()
            .anyRequest().authenticated()
            .and().oauth2Client()
            .and().oauth2Login();
    }
}

CORS配置

@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurer() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry
                    .addMapping("/api/myapp/**")
                    .allowedMethods("GET","POST","PUT","DELETE")
                    .allowedOrigins("http://localhost:7800");        
        }
    };
}

新版本(Spring Boot 3.1.3)配置

Security配置

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class OAuthSecurityConfig {
    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http              
                .cors(Customizer.withDefaults())
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests((authz) -> authz
                        .requestMatchers("/actuator/**").permitAll()                      
                        .anyRequest().authenticated())
                .oauth2Client(Customizer.withDefaults())
                .oauth2Login(Customizer.withDefaults());

         // done
        return http.build();
    }
}

CORS配置

@Bean
CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(List.of("http://localhost:7800"));
    configuration.setAllowedMethods(List.of("GET","POST","PUT","DELETE"));
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/api/myapp/**", configuration);
    return source;
} // end corsConfigurationSource()

请求与响应头信息

请求头(OPTIONS请求)

OPTIONS /oauth2/authorization/okta HTTP/1.1
Host: localhost:7801
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization
Referer: http://localhost:7800/
Origin: http://localhost:7800
Connection: keep-alive
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site

响应头

HTTP/1.1 403 
Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Transfer-Encoding: chunked
Date: Thu, 07 Sep 2023 12:45:00 GMT
Keep-Alive: timeout=60
Connection: keep-alive

控制台错误信息

跨域请求被阻止:同源策略不允许读取http://localhost:7801/oauth2/authorization/okta的远程资源。(原因:缺少CORS头‘Access-Control-Allow-Origin’)。状态码:403。

跨域请求被阻止:同源策略不允许读取http://localhost:7801/oauth2/authorization/okta的远程资源。(原因:CORS请求未成功)。状态码:(null)。

解决方案

1. 调整CORS配置范围

当前CORS仅对/api/myapp/**生效,但报错的是/oauth2/authorization/okta端点,需要将CORS规则覆盖到该端点:
修改corsConfigurationSource方法:

@Bean
CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(List.of("http://localhost:7800"));
    // 允许OPTIONS请求(浏览器预检请求)
    configuration.setAllowedMethods(List.of("GET","POST","PUT","DELETE","OPTIONS"));
    // 允许请求中的Authorization头
    configuration.setAllowedHeaders(List.of("Authorization", "Content-Type"));
    // 允许携带凭证(如果前端需要)
    configuration.setAllowCredentials(true);
    
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    // 同时覆盖API路径和OAuth2授权路径
    source.registerCorsConfiguration("/api/myapp/**", configuration);
    source.registerCorsConfiguration("/oauth2/authorization/**", configuration);
    return source;
}

2. 确保Security放行预检请求

在SecurityFilterChain中,需要明确允许OPTIONS请求通过,避免被认证拦截:
修改filterChain方法:

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http              
            .cors(Customizer.withDefaults())
            .csrf(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests((authz) -> authz
                    .requestMatchers("/actuator/**").permitAll()
                    // 放行所有OPTIONS请求,用于CORS预检
                    .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                    .anyRequest().authenticated())
            .oauth2Client(Customizer.withDefaults())
            .oauth2Login(Customizer.withDefaults());

     return http.build();
}

3. 验证OKTA配置

确认OKTA中的登录重定向URI和可信来源已包含http://localhost:7800,并且Spring Boot配置文件中的OKTA相关属性(如spring.security.oauth2.client.registration.okta.redirect-uri)与前端地址匹配。

原理说明

Spring Boot 3中Spring Security的CORS处理逻辑有所调整,预检OPTIONS请求会先经过Security过滤器链。如果未明确放行OPTIONS请求,会被anyRequest().authenticated()拦截返回403。同时,原CORS配置未覆盖OAuth2授权端点,导致该端点的跨域请求缺少必要的响应头。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 13:24:58