Spring Boot测试中如何清理Keycloak测试容器的数据库?
解决Testcontainers中Keycloak测试后的清理问题
方法一:通过Keycloak Admin API删除用户(推荐)
这种方式贴合Keycloak的官方使用规范,避免直接操作底层数据库带来的版本兼容性问题。
- 添加Keycloak Admin Client依赖
在pom.xml(Maven)中加入对应依赖:
<dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-admin-client</artifactId> <version>${keycloak.version}</version> <scope>test</scope> </dependency>
- 初始化Admin Client连接
在测试类中,通过容器提供的参数构建Admin Client:
private Keycloak keycloakAdminClient; @BeforeEach void initKeycloakAdmin() { keycloakAdminClient = KeycloakBuilder.builder() .serverUrl(keycloakContainer.getAuthServerUrl()) .realm("master") .username(keycloakContainer.getAdminUsername()) .password(keycloakContainer.getAdminPassword()) .clientId("admin-cli") .grantType(OAuth2Constants.PASSWORD) .build(); }
- 在@AfterEach中清理用户
如果测试中记录了创建的用户名/ID,可精准删除;也可批量清除测试realm中的非初始用户:
@AfterEach void cleanKeycloakUsers() { String testRealm = "your-test-realm"; // 替换为你导入的realm名称 // 方式1:删除指定测试用户(需提前保存用户ID) // keycloakAdminClient.realm(testRealm).users().get(targetUserId).remove(); // 方式2:批量清除测试realm中所有非初始用户 List<UserRepresentation> users = keycloakAdminClient.realm(testRealm).users().list(); for (UserRepresentation user : users) { // 排除预先导入的固定用户,比如admin或基础测试用户 if (!"initial-test-user".equals(user.getUsername())) { keycloakAdminClient.realm(testRealm).users().get(user.getId()).remove(); } } keycloakAdminClient.close(); }
方法二:直接操作Keycloak数据库(适合熟悉表结构的场景)
如果Keycloak使用外部数据库(如你项目中的MariaDB),可复用业务库的清理逻辑;若使用默认内置H2数据库,需按以下步骤操作:
- 获取H2数据库连接信息
Keycloak默认开启H2 TCP连接,端口为9092,需根据容器映射端口构建JDBC URL:
- WildFly版Keycloak数据路径:
/opt/jboss/keycloak/standalone/data/keycloak - Quarkus版Keycloak数据路径:
/opt/keycloak/data/keycloak
- 编写清理SQL脚本
创建clean_up_keycloak.sql,清理用户及关联表数据:
-- 删除非初始用户 DELETE FROM USER_ WHERE USERNAME NOT IN ('admin', 'initial-test-user'); -- 清理关联映射表 DELETE FROM USER_ROLE_MAPPING WHERE USER_ID NOT IN (SELECT ID FROM USER_ WHERE USERNAME IN ('admin', 'initial-test-user')); DELETE FROM USER_ATTRIBUTE WHERE USER_ID NOT IN (SELECT ID FROM USER_ WHERE USERNAME IN ('admin', 'initial-test-user'));
- 在@AfterEach中执行脚本
@AfterEach public void cleanUpKeycloakDb() throws Exception { String dbPath = "/opt/keycloak/data/keycloak"; // 根据Keycloak版本调整 String jdbcUrl = String.format("jdbc:h2:tcp://%s:%d/%s", keycloakContainer.getHost(), keycloakContainer.getMappedPort(9092), dbPath); try (Connection connection = DriverManager.getConnection(jdbcUrl, "sa", "")) { Resource resource = new ClassPathResource("/clean_up_keycloak.sql"); ScriptUtils.executeSqlScript(connection, resource); } }
注意事项
- 优先选择Admin API方式,Keycloak表结构可能随版本变更,直接操作数据库存在失效风险;
- 若Keycloak使用外部数据库(如MariaDB),需在容器初始化时指定数据库配置,复用业务库的连接方式清理即可。
内容的提问来源于stack exchange,提问作者Mátyás
相关产品推荐
相关产品推荐

