React前端向Spring Security发送Login POST请求遇CORS拦截问题
问题解决:React登录POST请求CORS报错处理
问题描述
即使禁用了CSRF并配置了CORS,React前端仍无法发送登录POST请求。前端可以正常注册新用户,但登录请求失败,报错信息如下:
Access to XMLHttpRequest at 'http://localhost:8080/login' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
通过Postman可以正常登录,确认问题完全与CORS相关。
已尝试方案
- 禁用CORS
- 在Spring中添加允许
localhost:3000的CORS配置,但未生效
代码片段
Spring WebSecurity配置
@Configuration @EnableWebSecurity public class WebSecurityConfig { @Autowired UserDetailsService userDetailsService; @Bean public AuthenticationManager authManager(HttpSecurity http) throws Exception { AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class); authenticationManagerBuilder.authenticationProvider(authenticationProvider()); authenticationManagerBuilder.userDetailsService(userDetailsService); return authenticationManagerBuilder.build(); } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests((requests) -> requests //permit routes to / and /home .antMatchers("/", "/home", "/signup", "/users", "/login") .permitAll() .anyRequest(). authenticated()) .cors().configurationSource(corsConfigurationSource()).and() .csrf() .disable() .formLogin() .defaultSuccessUrl("https://www.apple.com/", true); return http.build(); } @Bean public PasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("https://localhost:3000")); configuration.setAllowedMethods(Arrays.asList("GET","POST")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } public AuthenticationProvider authenticationProvider(){ DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); provider.setUserDetailsService(userDetailsService); provider.setPasswordEncoder(bCryptPasswordEncoder()); return provider; } }
React Login.js代码
function Login() { const [formData, setFormData] = useState({ username: '', password: '' }); const [usernameError, setUsernameError] = useState(''); const [passwordError, setPasswordError] = useState(''); const onUserNameChange = (e) => { setFormData({...formData, username: e.target.value}) } const onPasswordChange = (e) => { setFormData({...formData, password: e.target.value}) } const login = async (username, password) => { const response = await axios.post("http://localhost:8080/login", { password: formData.username, username: formData.password }) }; return ( <Container> <Typography variant='h4'>Login</Typography> <Stack spacing={2}> <TextField label='Username' onChange={onUserNameChange}/> { usernameError ? <span style={{ color: 'red', fontSize: '12px'}}>{usernameError}</span> : '' } <TextField label='Password' type="password" onChange={onPasswordChange}/> { passwordError ? <span style={{ color: 'red', fontSize: '12px'}}>{passwordError}</span> : '' } <Button variant='contained' onClick={login}>Login</Button> </Stack> </Container> ); } export default Login;
解决办法
1. 修正CORS配置的协议匹配问题
Spring配置中允许的源是https://localhost:3000,但前端实际运行在http://localhost:3000,协议不匹配导致CORS规则不生效。修改corsConfigurationSource中的允许源:
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
2. 调整Spring Security配置顺序
将CORS配置放在权限校验之前,确保CORS过滤器优先处理请求:
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .cors().configurationSource(corsConfigurationSource()).and() .csrf().disable() .authorizeHttpRequests((requests) -> requests .antMatchers("/", "/home", "/signup", "/users", "/login") .permitAll() .anyRequest().authenticated()) .formLogin() .defaultSuccessUrl("https://www.apple.com/", true); return http.build(); }
3. 修复前端请求参数错误
Login.js中axios请求的参数写反了username和password,修正后才能正常传递登录信息:
const login = async () => { try { const response = await axios.post("http://localhost:8080/login", { username: formData.username, password: formData.password }); // 处理登录成功逻辑 } catch (error) { console.error(error); // 处理错误提示 } };
额外优化建议
- 为CORS配置添加允许所有请求头,避免其他头信息导致的拦截:
configuration.setAllowedHeaders(Arrays.asList("*")); - Spring Security的
formLogin默认接受application/x-www-form-urlencoded格式的请求,如果前端发送JSON格式,需要额外配置支持JSON登录,或者修改前端请求的Content-Type。
内容的提问来源于stack exchange,提问作者Brandon Lei
相关产品推荐
相关产品推荐

