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

如何在不依赖外部库的情况下Mock Keycloak令牌测试Spring控制器?

解决Spring控制器测试中Mock Keycloak令牌的方案

因为@WithMockUser生成的是普通UserDetails类型的Principal,并非Keycloak专属的KeycloakPrincipal,所以强转时会出现空指针或类型转换异常。可以通过Spring Boot Test自带的Mockito手动Mock Keycloak相关对象,无需引入额外第三方库,具体步骤如下:

步骤1:在测试类中构建Mock的Keycloak认证链

在测试类的前置方法中,依次Mock AccessToken、KeycloakSecurityContext、KeycloakPrincipal,并将其组装成Authentication对象注入到SecurityContext中:

@SpringBootTest
@AutoConfigureMockMvc
class YourControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @BeforeEach
    void setUpKeycloakAuth() {
        // 模拟AccessToken,设置preferred_username声明
        AccessToken mockToken = Mockito.mock(AccessToken.class);
        // 注意:你的代码要转成Long,这里返回的字符串必须是数字格式
        Mockito.when(mockToken.getPreferredUsername()).thenReturn("123456");

        // 模拟KeycloakSecurityContext,关联上面的Token
        KeycloakSecurityContext mockSecurityContext = Mockito.mock(KeycloakSecurityContext.class);
        Mockito.when(mockSecurityContext.getToken()).thenReturn(mockToken);

        // 模拟KeycloakPrincipal,关联SecurityContext
        KeycloakPrincipal mockPrincipal = Mockito.mock(KeycloakPrincipal.class);
        Mockito.when(mockPrincipal.getKeycloakSecurityContext()).thenReturn(mockSecurityContext);

        // 构建Authentication对象,将Mock的Principal传入
        Authentication auth = new UsernamePasswordAuthenticationToken(
                mockPrincipal,
                null, // 凭证无需模拟
                Collections.emptyList() // 权限可根据测试需求添加
        );

        // 将Authentication设置到SecurityContext
        SecurityContextHolder.getContext().setAuthentication(auth);
    }

    // 测试结束后清理SecurityContext,避免测试污染
    @AfterEach
    void clearAuthContext() {
        SecurityContextHolder.clearContext();
    }

    @Test
    void testProtectedEndpoint() throws Exception {
        mockMvc.perform(get("/your-protected-endpoint"))
                .andExpect(status().isOk());
    }
}

关键说明

  1. 这里使用的Mockito是Spring Boot Test依赖自带的组件,不需要额外引入第三方库,符合你的需求。
  2. 确保preferred_username返回的字符串是可转换为Long的数字格式,否则会触发NumberFormatException。
  3. 如果需要模拟其他令牌声明(如roles、email等),只需在Mock AccessToken时添加对应的when语句即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 08:09:19