React+Spring Boot中Axios POST请求CSRF配置及登录CORS错误排查
问题分析与解决方案
看起来你遇到的核心问题是CORS配置的允许请求头与实际发送的请求头不匹配,再加上Axios的CSRF令牌传递方式有误,导致预请求(OPTIONS)失败。下面一步步帮你修正:
1. 修正CORS配置的允许请求头
你的错误提示明确说x-xsrf-token不被Access-Control-Allow-Headers允许,但看你的CORS配置里只加了xsrf-token,而实际请求里发送的是X-XSRF-TOKEN(注意大小写)。另外,当开启AllowCredentials=true时,AllowedOrigins不能用*,必须指定具体的前端域名,否则浏览器会拒绝跨域请求。修改后的CORS配置如下:
@Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); // 替换为你的React实际域名,不能用* configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")); configuration.setAllowCredentials(true); // 加入实际发送的X-XSRF-TOKEN请求头 configuration.setAllowedHeaders(Arrays.asList("authorization", "Cache-Control", "content-type", "X-XSRF-TOKEN")); configuration.setExposedHeaders(Arrays.asList("X-XSRF-TOKEN")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; }
2. 修正Axios的请求配置
你把Axios的xsrfCookieName和xsrfHeaderName放在了headers里,这是错误的——这两个是Axios的全局/请求配置项,不是请求头的一部分。另外,Spring Security启用CSRF时,通过X-XSRF-TOKEN头传递令牌就足够了,不需要再在表单里加_csrf参数。修改后的Axios代码:
export const addProjectTask = (username,password,csrf,history) => async dispatch => { axios.post('http://localhost:8080/login', Qs.stringify({ username: username, password: password }), { headers: { "X-XSRF-TOKEN": csrf, "Content-Type": "application/x-www-form-urlencoded" }, credentials: 'include', }) .then(function (response) { console.log(response); history.push("/"); }) .catch(function (error) { console.log(error); }); };
3. 确保Spring Security中CORS与CSRF的顺序正确
在Spring Security配置类中,必须让CORS过滤器优先于CSRF过滤器生效,同时建议配置CookieCsrfTokenRepository,方便后续扩展(比如让Axios自动从Cookie读取令牌):
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CorsConfigurationSource corsConfigurationSource; @Override protected void configure(HttpSecurity http) throws Exception { http // 先启用CORS,确保CORS过滤器在CSRF之前执行 .cors().configurationSource(corsConfigurationSource) .and() .csrf() // 设置Cookie的HttpOnly为false,允许前端读取XSRF-TOKEN Cookie .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .and() .authorizeRequests() .antMatchers("/login").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginProcessingUrl("/login"); // 指定登录接口路径 } }
4. 验证请求与响应头
修改完成后,打开Chrome开发者工具的Network标签:
- 查看OPTIONS预请求的响应头,确认
Access-Control-Allow-Headers包含X-XSRF-TOKEN - 查看POST登录请求的请求头,确认
X-XSRF-TOKEN已正确携带
内容的提问来源于stack exchange,提问作者vidy
相关产品推荐
相关产品推荐

