Spring Security 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
相关产品推荐
相关产品推荐

