本文旨在解决Spring Boot应用集成Spring Security后,前端React应用调用Stripe支付接口时遇到的CORS(跨域资源共享)问题。通过分析Spring Security配置、CORS配置以及前端代码,提供了一套完整的解决方案,帮助开发者正确配置CORS,确保Stripe支付功能的正常运行。重点在于理解CORS机制,并结合Spring Security的特性进行配置,最终实现前后端安全可靠的交互。
CORS (Cross-Origin Resource Sharing) 是一种浏览器安全机制,用于限制从一个源(域、协议和端口)发起的HTTP请求访问另一个源的资源。 当浏览器检测到跨域请求时,会先发送一个"预检"(preflight)请求(OPTIONS方法)到服务器,以确认服务器是否允许该跨域请求。
Spring Security作为一个强大的安全框架,默认情况下会拦截所有请求,包括CORS预检请求。 因此,我们需要正确配置Spring Security,使其允许来自特定源的跨域请求。
解决此问题的关键在于正确配置CORS,并确保Spring Security不会错误地阻止Stripe的请求。 以下步骤提供了一种全面的解决方案:
1. 移除前端代码中不必要的CORS Header设置
在前端代码 ProfilPayment.java 中,你手动设置了 Access-Control-Allow-Origin 等header。这些header应该由服务器端设置,而不是客户端。移除以下代码:
const headers = {
'Content-Type': 'application/json',
"Access-Control-Allow-Origin": "*", // 移除
'Access-Control-Allow-Methods': "*", // 移除
'Authorization': `Bearer ${localStorage.getItem("token")}`
}
//修改为:
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem("token")}`
}2. 确保CORS配置正确
检查 CorsConfiguration.java 中的CORS配置。 确保允许前端应用的源(例如 http://localhost:3000)以及Stripe的必要域名。
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH", "OPTIONS")
.allowedOrigins("http://localhost:3000") // 替换为你的前端应用域名
.exposedHeaders("*")
.allowedHeaders("*")
.allowCredentials(true); // 允许携带cookie,如果需要的话
}
};
}
}注意事项:
3. Spring Security配置调整
确保Spring Security的配置允许CORS预检请求。 一种方法是在 SecurityConfig.java 中添加一个 CorsFilter bean。 这种方法通常比使用 WebMvcConfigurer 更可靠,尤其是在处理复杂的安全配置时。
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import java.util.Arrays; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { // 注入你的 JWT 过滤器 private final JwtFilter jwtFilter; public SecurityConfig(JwtFilter jwtFilter) { this.jwtFilter = jwtFilter; } @Override protected void configure(HttpSecurity http) throws Exception { String[] staticResources = { "/api/clients/authentication/**", "/api/repas/**" }; http.cors().and().csrf().disable() .exceptionHandling() .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers(staticResources).permitAll() .anyRequest().authenticated(); http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class); // 调整过滤器顺序 } @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); // 替换为你的前端应用域名 configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token")); configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } @Bean public CorsFilter corsFilter() { return new CorsFilter(corsConfigurationSource()); } }
解释:
关键点:
4. 检查Stripe域名
确认你使用的Stripe API域名是否需要添加到CORS允许列表中。虽然 r.stripe.com 主要用于跟踪,但确保用于实际支付请求的域名(例如 api.stripe.com)也在你的CORS配置中。通常情况下,Stripe SDK会自动处理与Stripe API的交互,所以你可能不需要显式地添加api.stripe.com到allowedOrigins。
5. 测试与调试
完成上述配置后,重新启动你的Spring Boot应用和React应用。 使用浏览器的开发者工具检查网络请求,查看CORS相关的header是否正确设置。 确保没有CORS错误。
总结
解决Spring Security和Stripe集成中的CORS问题需要仔细配置CORS和Spring Security。 通过移除前端不必要的CORS header,正确配置Spring Security和CORS过滤器,并验证Stripe域名,可以确保你的应用能够安全地处理Stripe支付请求。记住,安全至关重要,始终使用最小权限原则,并避免在生产环境中使用通配符(*)作为允许的源。