You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动