配置CORS映射后Spring Security WebFlux仍存在跨域问题
问题分析与解决
你的配置存在以下几个问题,导致CORS策略失效:
1. CORS配置中allowedOrigins格式错误
浏览器的Origin包含协议前缀(如http://localhost:4200),你当前配置的localhost:4200缺少协议,导致CORS规则无法匹配请求的Origin,服务器不会返回Access-Control-Allow-Origin响应头。
2. 重复定义ReactiveAuthenticationManager Bean
你同时定义了两个ReactiveAuthenticationManager类型的Bean,Spring容器无法确定使用哪一个,会导致认证流程异常,进而影响请求处理(包括CORS响应头的生成)。
3. allowedHeaders包含无效的响应头字段
Access-Control-Allow-Origin是服务器返回的响应头,不是客户端请求的头字段,不需要添加到allowedHeaders中,该配置项仅用于指定允许的请求头。
4. Preflight(OPTIONS)请求被认证拦截
浏览器发送的CORS预请求(OPTIONS)不会携带认证信息,但你的安全配置中设置了anyExchange().authenticated(),导致OPTIONS请求被拦截,无法正常返回CORS响应头。
修正后的配置代码
1. 修正CORS配置(WebConfig.java)
@Configuration @EnableWebFlux public class WebConfig implements WebFluxConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 补充协议前缀 .allowedOrigins("http://localhost:4200") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 移除无效的响应头,保留实际需要的请求头 .allowedHeaders("Authorization", "Content-Type") // 允许携带认证信息(HTTP Basic认证需要) .allowCredentials(true); } }
2. 修正安全配置(SecurityConfig.java)
移除重复的ReactiveAuthenticationManager Bean,同时允许OPTIONS请求无需认证:
@Configuration @EnableReactiveMethodSecurity @EnableWebFluxSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http){ return http .cors().and() .csrf().disable() .authorizeExchange() // 允许OPTIONS请求无需认证,处理CORS预请求 .pathMatchers(HttpMethod.OPTIONS).permitAll() // 其他请求需要认证 .anyExchange().authenticated() .and() .httpBasic() .and() .build(); } // 保留一个正确的ReactiveAuthenticationManager Bean @Bean public ReactiveAuthenticationManager authenticationManager(ReactiveUserDetailsService userDetailsService, PasswordEncoder passwordEncoder){ UserDetailsRepositoryReactiveAuthenticationManager manager = new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService); manager.setPasswordEncoder(passwordEncoder); return manager; } @Bean public PasswordEncoder noPasswordEncoder(){ return NoOpPasswordEncoder.getInstance(); } }
额外说明
allowCredentials(true)必须设置,因为HTTP Basic认证需要携带用户凭证,浏览器要求服务器明确允许该属性才能发送认证信息。- 确保你的Angular请求中设置了
withCredentials: true(使用HttpClient时),例如:
this.http.get('http://localhost:8080/course/my-courses', { withCredentials: true });
内容的提问来源于stack exchange,提问作者Kantenburg
相关产品推荐
相关产品推荐

