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

Spring Boot 3控制器层单元测试:认证环节空指针异常

问题分析与解决方案

空指针异常原因

  1. 测试环境默认spring.security.enabled=false,此时WebSecurityConfig中的认证逻辑未生效,即使添加@WithMockUser注解,请求也不会被Spring Security处理,导致控制器方法的Principal参数为null。
  2. getUserInfo方法未对Principal为null的情况做校验,直接进行类型强转,触发空指针异常。

解决方案

方案一:测试时启用Security配置

在测试类上添加属性配置,强制开启Security,让@WithMockUser能正常注入认证信息:

@ExtendWith(MockitoExtension.class)
@WebMvcTest(SMVConfigController.class)
@TestPropertySource(properties = "spring.security.enabled=true") // 新增该行
class SMVConfigControllerTest {
    // 原有测试代码保持不变
}

方案二:完善控制器空指针防护

在getUserInfo方法中先判断Principal是否为null,避免空指针:

private UserInfo getUserInfo(Principal principal){
    if(principal == null){
        // 根据业务需求处理:返回默认匿名用户或抛出异常
        return UserInfo.builder().username("anonymous").build();
        // 也可抛出异常:throw new IllegalAccessException("请求未完成认证");
    }
    if(principal instanceof JwtAuthenticationToken) {
        return userInfoHelper.getUserInfo(((JwtAuthenticationToken) principal).getToken().getTokenValue());
    }else if(principal instanceof UsernamePasswordAuthenticationToken) {
        User user = (User)((UsernamePasswordAuthenticationToken) principal).getPrincipal();
        return UserInfo.builder().username(user.getUsername()).build();
    }else{
        // 处理其他未知类型的Principal
        return UserInfo.builder().username("unknown").build();
    }
}

方案三:测试时手动注入认证信息

如果不想开启Security配置,可通过SecurityMockMvcRequestPostProcessors手动给请求添加认证对象:

@Test
void addSmvConfigTest() throws Exception{
    Gson gson = new GsonBuilder()
            .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer())
            .create();
    SmvDTO smvDto = SmvConfigSampleData.createSampleDto();
    
    // 构造测试用的认证对象
    User testUser = new User("TEST_USER", "", Collections.emptyList());
    UsernamePasswordAuthenticationToken authToken = 
        new UsernamePasswordAuthenticationToken(testUser, null, testUser.getAuthorities());
    
    RequestBuilder addSmvConfigRequestBuilder = MockMvcRequestBuilders.post(basePath + "/")
            .contentType(MediaType.APPLICATION_JSON)
            .content(gson.toJson(smvDto))
            .accept(MediaType.APPLICATION_JSON)
            .with(SecurityMockMvcRequestPostProcessors.authentication(authToken)); // 注入认证信息

    when(smvConfigService.saveSmvConfig(any(), any())).thenReturn(SmvConfigSampleData.createSampleDto());
    mockMvc.perform(addSmvConfigRequestBuilder).andExpect(status().isOk());
}

Postman测试说明

UsernamePasswordAuthenticationToken是Spring Security内部的认证对象,Postman无法直接发送。实际场景处理方式:

  • 若securityEnabled=true:通过OAuth2流程获取JWT Token,在请求头添加Authorization: Bearer <token>,控制器会自动接收JwtAuthenticationToken类型的Principal。
  • 若securityEnabled=false:依赖控制器中对Principal为null的处理逻辑,或自定义请求头传递用户信息(仅用于临时测试)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 09:57:53