如何在不依赖外部库的情况下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()); } }
关键说明
- 这里使用的Mockito是Spring Boot Test依赖自带的组件,不需要额外引入第三方库,符合你的需求。
- 确保
preferred_username返回的字符串是可转换为Long的数字格式,否则会触发NumberFormatException。 - 如果需要模拟其他令牌声明(如roles、email等),只需在Mock
AccessToken时添加对应的when语句即可。
内容的提问来源于stack exchange,提问作者horsemanwithnoname
相关产品推荐
相关产品推荐

