
spring boot 3.x 中启用 basic auth 后 post 接口持续返回 403,通常并非认证失败,而是默认开启的 csrf 防护机制拦截了无有效 csrf token 的请求;关闭 csrf(适用于 rest api)或显式携带 token 即可解决。
spring boot 3.x 中启用 basic auth 后 post 接口持续返回 403,通常并非认证失败,而是默认开启的 csrf 防护机制拦截了无有效 csrf token 的请求;关闭 csrf(适用于 rest api)或显式携带 token 即可解决。
在 Spring Security 6+(对应 Spring Boot 3.0+)中,HttpSecurity 的配置方式已全面迁移到基于 SecurityFilterChain 的函数式风格。你遇到的 403 Forbidden 并非由用户名/密码错误或权限不足导致,而是一个典型的CSRF(跨站请求伪造)拦截现象:Spring Security 默认对所有非幂等请求(如 POST、PUT、DELETE)强制校验 CSRF Token,即使用户已通过 Basic Authentication 成功认证,若请求未携带合法 Token,仍会直接拒绝并返回 403。
✅ 正确配置:为 REST API 禁用 CSRF
对于纯 RESTful API 场景(推荐使用 Authorization: Basic ... 或 Bearer Token 认证,而非 Cookie),CSRF 保护既无必要也不适用——因为攻击者无法在第三方站点中可靠地复用 Basic Auth 凭据(浏览器不会自动附加 Authorization 头)。因此,应显式禁用 CSRF:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.anyRequest().authenticated() // 所有请求需认证
)
.httpBasic(Customizer.withDefaults()) // 启用 Basic Auth
.csrf(csrf -> csrf.disable()); // ? 关键:禁用 CSRF
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withUsername("user")
.password(passwordEncoder().encode("password"))
.roles("USER_ROLE")
.build();
return new InMemoryUserDetailsManager(user);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(8);
}
}⚠️ 注意:authorizeRequests() 已被弃用,务必使用 authorizeHttpRequests();httpBasic() 需配合 Customizer.withDefaults()(Spring Security 6.1+ 推荐写法)。
? 单元测试中的 CSRF 处理
若你在集成测试中使用 MockMvc,且未禁用 CSRF,则必须为每个 POST 请求显式添加 CSRF Token:
@Test
void createReceipt_withValidCredentials_shouldReturnOk() throws Exception {
mockMvc.perform(post("/person/100")
.with(httpBasic("user", "password")) // Basic Auth 凭据
.with(csrf())) // ? 添加 CSRF Token
.andExpect(status().isOk());
}
@Test
void createReceipt_wrongPassword_shouldReturnUnauthorized() throws Exception {
mockMvc.perform(post("/person/100")
.with(httpBasic("user", "wrong"))) // 密码错误 → 401
.andExpect(status().isUnauthorized());
}@WithMockUser 或 authentication(...) 在测试中不能替代 CSRF Token;csrf() 是 CsrfRequestPostProcessor 的便捷封装,会自动生成并注入合法 Token。
? 补充说明与最佳实践
- 不要混淆 CORS 与 CSRF:CORS 控制前端跨域访问权限,而 CSRF 是服务端对“伪造请求”的防护机制。本例中 403 明确由 InvalidCsrfTokenException 触发,可通过日志或断点验证。
- 生产环境建议:若 API 同时支持 Cookie 登录(如管理后台),则应保留 CSRF 并配合 SameSite=Strict Cookie 策略;但面向移动端或前端 SPA 的 REST API,禁用 CSRF 是标准做法。
-
安全加固提醒:禁用 CSRF 后,请确保:
- 不在响应中设置敏感 Cookie(尤其是 JSESSIONID);
- 使用 Authorization 头而非 Cookie 传递凭证;
- 对敏感操作增加二次确认(如 OTP、操作密码)。
通过上述调整,你的 /person/{id} POST 接口将正常响应 200 OK 或业务状态码,不再无故返回 403。核心原则是:CSRF 保护与认证方式必须匹配——Cookie 认证需 CSRF,Token 认证则无需 CSRF。










