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

控制器测试中@WithUserDetails能否正常注入@AuthenticationPrincipal?

问题产生的核心原因
  • 测试环境未启用Spring Security过滤器链:MockMvc默认不会加载安全过滤器,@WithUserDetails生成的认证上下文无法传递到控制器层,导致@AuthenticationPrincipal无法拿到对应对象
  • UserDetailsService返回类型不匹配:@WithUserDetails会调用测试环境中配置的UserDetailsService#loadUserByUsername方法获取用户对象,如果返回类型不是你自定义的AuthenticatedUser,会因为类型不匹配无法注入,最终显示为null
  • 测试类缺少安全测试注解:如果是仅加载Controller层的单元测试,需要额外添加@AutoConfigureMockMvc、@AutoConfigureSecurity等注解启用安全相关自动配置
具体解决步骤
  1. 初始化MockMvc时启用安全过滤器配置
    在测试类的初始化方法中添加springSecurity()配置,示例代码:
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;

@Autowired
private WebApplicationContext webApplicationContext;

private MockMvc mockMvc;

@BeforeEach
void initMockMvc() {
    mockMvc = MockMvcBuilders
            .webAppContextSetup(webApplicationContext)
            .apply(springSecurity()) // 关键配置,加载安全过滤器链
            .build();
}
  1. 校验测试环境的UserDetailsService实现
    确保测试环境注入的UserDetailsService的loadUserByUsername方法返回值就是AuthenticatedUser类型,不要返回默认的org.springframework.security.core.userdetails.User类。如果使用@WebMvcTest进行 slim 层测试,需要通过@MockBean模拟UserDetailsService,并指定mock返回的AuthenticatedUser对象。
  2. 备选方案:手动注入认证上下文
    如果上述配置后仍有问题,可以跳过@WithUserDetails注解,直接在测试方法中手动设置安全上下文,示例代码:
@Test
void shouldCreateVote_whenPost() throws Exception {
    // 构造测试用的AuthenticatedUser对象
    AuthenticatedUser authenticatedUser = new AuthenticatedUser(BASIC_USER_ENTITY);
    // 生成认证对象
    Authentication authentication = new UsernamePasswordAuthenticationToken(
            authenticatedUser,
            null,
            authenticatedUser.getAuthorities()
    );
    // 写入安全上下文
    SecurityContextHolder.getContext().setAuthentication(authentication);

    mockMvc.perform(
                    post("/vote")
                            .contentType(MediaType.APPLICATION_JSON)
                            .content(objectMapper.writeValueAsString(VOTE_CREATION_ADRIANO))
            )
            .andExpect(status().isCreated());
    Mockito.verify(voteService, times(1))
            .addVote(refEq(BASIC_USER_ENTITY), refEq(VOTE_CREATION_ADRIANO));
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 20:09:04