Spring Boot中带Spring Security的Rest接口单元测试403问题排查
解决Spring Boot单元测试中始终返回403的问题
我太懂这种明明配置了权限规则,结果单元测试里全是403的挫败感了——本来应该聚焦接口逻辑,结果卡在安全校验上浪费时间。咱们一步步拆解可能的问题,逐个排查:
1. 先补全你的Security配置,重点检查这两点
从你贴的代码片段来看,大概率是配置没写完整。针对你的需求(未登录仅允许GET请求),正确的配置应该包含这两个关键部分:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // 配置请求权限规则 .authorizeHttpRequests(auth -> auth .requestMatchers(HttpMethod.GET, "/**").permitAll() // 开放所有GET请求 .anyRequest().authenticated() // 其他请求必须登录 ) // 单元测试必加:禁用CSRF保护 .csrf(csrf -> csrf.disable()); return http.build(); } }
这里最容易踩坑的是CSRF禁用:Spring Security默认开启CSRF校验,单元测试里如果没携带CSRF Token,POST/PUT/DELETE这类请求会直接被拦截返回403——哪怕你配置了permitAll也没用。
2. 单元测试的配置要跟上
很多时候不是后端配置有问题,是测试环境的Security没配置对:
- 如果你用
@WebMvcTest测试Controller,记得导入你的SecurityConfig,否则测试环境会用默认的Security规则(全接口需要认证); - 如果只是想单纯测试接口逻辑,不想被Security干扰,可以直接在测试类里关闭安全过滤器,或者在
application-test.properties里禁用Security。
给你几个实用的测试示例:
// 测试带Security规则的场景 @WebMvcTest(YourRestController.class) @Import(SecurityConfig.class) // 导入你的安全配置 class YourRestControllerTest { @Autowired private MockMvc mockMvc; // 测试未登录访问GET接口:应该返回200 @Test void testGetEndpoint_AnonymousAccess_Ok() throws Exception { mockMvc.perform(get("/api/your-resource")) .andExpect(status().isOk()); } // 测试未登录访问POST接口:应该返回403 @Test void testPostEndpoint_AnonymousAccess_Forbidden() throws Exception { mockMvc.perform(post("/api/your-resource") .contentType(MediaType.APPLICATION_JSON) .content("{\"name\": \"test\"}")) .andExpect(status().isForbidden()); } // 测试登录用户访问POST接口:应该返回200 @Test void testPostEndpoint_AuthenticatedAccess_Ok() throws Exception { mockMvc.perform(post("/api/your-resource") .with(user("test-user").roles("USER")) // 模拟登录用户 .contentType(MediaType.APPLICATION_JSON) .content("{\"name\": \"test\"}")) .andExpect(status().isOk()); } }
如果想彻底在测试里关闭Security,可以这么做:
@WebMvcTest(YourRestController.class) @AutoConfigureMockMvc(addFilters = false) // 关闭所有Security过滤器 class YourRestControllerTest { // ... 测试逻辑 }
或者在src/test/resources/application-test.properties里加一行:
spring.security.enabled=false
3. 排查隐藏的权限拦截
如果上面两步都没问题,那得看看有没有其他拦截逻辑:
- 检查Controller方法上有没有加
@PreAuthorize/@PostAuthorize这类方法级权限注解,这些注解的优先级比HttpSecurity的配置更高; - 确认项目里有没有自定义的Security过滤器,比如JWT校验过滤器,可能过滤器里的逻辑导致了403;
- 打开Security的调试日志,看具体的决策过程:在
application-test.properties里加logging.level.org.springframework.security=DEBUG,日志会告诉你哪个规则匹配了请求,为什么返回403。
4. 最后确认请求路径匹配
有时候配置的requestMatchers路径和测试里的请求路径不匹配,比如你配置的是/api/**,但测试请求的是/your-resource,这时候会走到默认的anyRequest().authenticated()规则,导致403。用上面的调试日志就能快速发现这个问题。
内容的提问来源于stack exchange,提问作者needoriginalname




