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

Spring Boot WebMvcTest测试JWT接口时注入AuthenticationPrinciple方法

问题根因

@WebMvcTest 是Spring Boot提供的MVC层切片测试注解,默认仅加载Web层相关组件(控制器、视图解析器、MVC拦截器、Spring Security默认Web安全配置等),不会加载业务层、持久层Bean,也不会自动装配自定义的CustomUserDetailsService等安全相关业务组件。两类报错的核心原因分别是:

  • 项目自定义的Spring Security配置依赖了CustomUserDetailsService,但切片上下文里不存在该Bean,因此抛出NoSuchBeanDefinitionException
  • 手动传递的AUTH_HEADER未被完整安全过滤链解析(相关认证逻辑依赖的Bean未加载),SecurityContext中无有效认证信息,因此控制器方法中@AuthenticationPrincipal注入的参数为null
实现方案

1. 引入Spring Security测试组件

在测试作用域引入spring-security-test依赖,Maven配置如下:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>

Gradle配置如下:

testImplementation 'org.springframework.security:spring-security-test'

2. 模拟安全配置依赖的业务Bean

在测试类中通过@MockBean注解注入CustomUserDetailsService的模拟实例,保证Spring Security配置可以正常初始化,不需要实现真实的数据库查询逻辑。如果自定义安全配置还依赖JWT解析、权限校验等其他业务Bean,统一通过@MockBean注入模拟实例即可。

3. 直接构造认证信息绑定到请求上下文

不需要手动拼接Token走完整认证流程,通过spring-security-test提供的工具直接构造认证后请求,即可让@AuthenticationPrincipal正常注入参数,两种常用实现方式:

快速模拟场景:@WithMockUser注解

适合不需要自定义用户主体字段的简单校验场景:

@Test
@WithMockUser(username = "testUser", roles = "USER")
void test_get() throws Exception {
    mockMvc.perform(get("/your/api/path"))
            .andExpect(status().isOk());
}

自定义主体场景:RequestPostProcessor构造自定义UserPrinciple

如果控制器逻辑强依赖自定义UserPrinciple中的业务字段(如用户ID、权限集合等),直接构造测试用的UserPrinciple对象绑定到请求:

@Test
void test_get() throws Exception {
    // 构造业务侧定义的UserPrinciple测试实例
    UserPrinciple testUser = new UserPrinciple();
    testUser.setId(1L);
    testUser.setUsername("testUser");
    testUser.setRoles(Set.of("ROLE_USER"));

    mockMvc.perform(get("/your/api/path")
                    .with(user(testUser).roles("USER")))
            .andExpect(status().isOk());
}

该写法会直接将构造的testUser对象绑定到控制器方法的@AuthenticationPrincipal参数,不会出现空指针问题。

完整测试类参考

@WebMvcTest(controllers = DemoController.class)
// 存在自定义Spring Security配置类时添加@Import导入,使用默认安全配置可省略
@Import(SecurityConfig.class)
class DemoControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private CustomUserDetailsService customUserDetailsService;
    // 控制器依赖的其他业务Service同样通过@MockBean注入模拟实例
    // @MockBean
    // private DemoBizService demoBizService;

    @Test
    void test_get() throws Exception {
        UserPrinciple testUser = new UserPrinciple();
        testUser.setId(1L);
        testUser.setUsername("test");

        mockMvc.perform(get("/demo")
                        .with(user(testUser)))
                .andExpect(status().isOk());
    }
}

补充说明:如果项目使用JWT认证,也可以为测试环境单独编写极简安全配置,直接放开接口认证规则、或者注册测试专用的轻量认证过滤器,不需要加载生产环境的完整JWT解析逻辑,可进一步提升切片测试的执行速度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 15:24:34