You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security REST单元测试返回401 Unauthorized状态码问题

解决Spring REST单元测试返回401 Unauthorized的问题

我来帮你排查下这个401的问题,这种情况在自定义API Key认证的测试场景里挺常见的,咱们一步步拆解可能的原因和解决办法:

1. 确认测试中是否正确模拟了ApiKeyRepository

你的安全配置依赖ApiKeyRepository来验证API Key的合法性,单元测试时如果没有模拟这个Repository的返回值,会导致认证逻辑找不到合法的Key,直接返回401。

解决办法:用Mockito模拟Repository的行为,确保测试时能返回一个有效的ApiKey记录:

@MockBean
private ApiKeyRepository apiKeyRepository;

@BeforeEach
void setUp() {
    // 模拟当传入任意字符串时,返回一个合法的ApiKey对象
    when(apiKeyRepository.findByKey(anyString())).thenReturn(Optional.of(new ApiKey("test-valid-key")));
}

2. 测试请求是否携带了正确的API Key请求头

自定义API Key认证通常依赖请求头(比如X-API-Key)传递密钥,如果测试时没加这个头,或者头名称和过滤器里的不一致,肯定会认证失败。

确保测试请求里添加了正确的请求头:

mockMvc.perform(get("/api/your-target-endpoint")
        .header("X-API-Key", "test-valid-key")) // 这里的头名称要和过滤器里获取的一致
        .andExpect(status().isOk());

3. 检查ApiKeyAuthFilter的配置和逻辑

你的代码里提到了ApiKeyAuthFilter,如果过滤器没有正确加入Spring Security的过滤器链,或者内部认证逻辑有问题,也会导致401:

  • 首先确认在安全配置里把过滤器加到了正确的位置:
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
        .csrf().disable() // REST接口一般不需要CSRF保护,禁用避免干扰
        .authorizeRequests()
        .anyRequest().authenticated()
        .and()
        // 把自定义过滤器加到用户名密码过滤器之前
        .addFilterBefore(apiKeyAuthFilter(), UsernamePasswordAuthenticationFilter.class);
}

@Bean
public ApiKeyAuthFilter apiKeyAuthFilter() throws Exception {
    ApiKeyAuthFilter filter = new ApiKeyAuthFilter();
    // 必须设置AuthenticationManager,否则过滤器无法完成认证
    filter.setAuthenticationManager(authenticationManager());
    return filter;
}
  • 然后检查过滤器的doFilterInternal方法,确保正确获取请求头并完成认证:
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    // 这里的头名称要和测试里的一致
    String apiKey = request.getHeader("X-API-Key");
    if (apiKey != null && !apiKey.isBlank()) {
        // 构造API Key认证对象
        Authentication authRequest = new ApiKeyAuthenticationToken(apiKey, null);
        // 调用认证管理器完成认证
        Authentication authResult = getAuthenticationManager().authenticate(authRequest);
        // 将认证结果存入安全上下文
        SecurityContextHolder.getContext().setAuthentication(authResult);
    }
    filterChain.doFilter(request, response);
}

4. 确认测试类的配置是否正确

如果用@WebMvcTest测试控制器,需要手动导入你的ApiSecurityConfig,否则Spring不会加载自定义的安全配置:

@WebMvcTest(YourRestController.class)
@Import(ApiSecurityConfig.class) // 导入自定义安全配置类
class YourRestControllerTest {
    @Autowired
    private MockMvc mockMvc;

    // 其他测试代码...
}

如果用@SpringBootTest集成测试,记得加上@AutoConfigureMockMvc来自动配置MockMvc:

@SpringBootTest
@AutoConfigureMockMvc
class YourIntegrationTest {
    @Autowired
    private MockMvc mockMvc;

    // 其他测试代码...
}

5. 排查是否有其他安全配置冲突

你的安全配置用了@Order(1),如果项目里还有其他安全配置类,可能存在优先级冲突,导致你的API Key认证逻辑没生效。可以暂时去掉@Order或者调整优先级,确保当前配置是第一个被加载的。


内容的提问来源于stack exchange,提问作者Dullimeister

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:48:48