Keycloak SPI中使用quarkus-rest-client-reactive-jackson遇类缺失错误求助
解决Keycloak 23.0.3自定义SPI中Quarkus Reactive Rest Client类找不到的问题
问题根源
- 依赖版本不匹配:Keycloak 23.0.3基于Quarkus 3.2.9.Final,你使用的
quarkus-rest-client-reactive-jackson3.6.3版本过高,与Keycloak内置Quarkus版本冲突,引发类加载异常。 - 依赖Scope错误:将
quarkus-rest-client-reactive-jackson设为<scope>provided</scope>,但Keycloak服务器并未内置该依赖,导致运行时找不到相关类。 - 依赖未正确打包:仅将SPI jar和零散依赖放入
providers文件夹,无法保证Quarkus reactive组件的类加载兼容性。
具体解决方案
1. 修正Pom.xml依赖配置
- 调整
quarkus-rest-client-reactive-jackson的版本为Keycloak对应Quarkus版本(3.2.9.Final),并将Scope改为compile(需打包进SPI jar):
<!-- 替换原rest client依赖 --> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-rest-client-reactive-jackson</artifactId> <version>3.2.9.Final</version> <scope>compile</scope> </dependency>
- 添加MicroProfile Rest Client API依赖(确保
RestClientBuilder类存在):
<dependency> <groupId>org.eclipse.microprofile.rest.client</groupId> <artifactId>microprofile-rest-client-api</artifactId> <version>3.0</version> <scope>compile</scope> </dependency>
2. 使用Maven Shade插件打包Fat Jar
Keycloak的SPI需要将所有依赖打包进单个jar,确保类加载路径正确。在Pom.xml中添加Shade插件配置:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.5.0</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <createDependencyReducedPom>false</createDependencyReducedPom> <filters> <filter> <artifact>*:*</artifact> <excludes> <!-- 排除Keycloak提供的依赖,避免冲突 --> <exclude>META-INF/services/org.keycloak.provider.ProviderFactory</exclude> <exclude>META-INF/quarkus-*.properties</exclude> </excludes> </filter> </filters> </configuration> </execution> </executions> </plugin> </plugins> </build>
执行mvn clean package,生成包含所有依赖的Fat Jar。
3. 正确部署SPI
- 将生成的Fat Jar复制到Keycloak的
providers目录。 - 运行Keycloak的构建命令,让服务器扫描并加载SPI:
# Linux/macOS ./kc.sh build # Windows kc.bat build
- 重启Keycloak服务器。
4. 可选:改用Keycloak内置的Rest客户端工具
如果不想处理Quarkus依赖冲突,可以直接使用Keycloak内置的org.keycloak.common.util.HttpClient工具类,无需额外引入依赖,适用于简单REST请求场景:
HttpClient client = HttpClientFactory.createDefault(); HttpPost post = new HttpPost("http://localhost:8080/my-path/token"); // 设置请求参数 List<NameValuePair> params = new ArrayList<>(); params.add(new BasicNameValuePair("client_id", CLIENT_ID)); params.add(new BasicNameValuePair("client_secret", CLIENT_SECRET)); params.add(new BasicNameValuePair("grant_type", "client_credentials")); post.setEntity(new UrlEncodedFormEntity(params)); // 设置Header post.addHeader("User-Id", userId.toString()); // 执行请求并解析响应 HttpResponse response = client.execute(post); String responseBody = EntityUtils.toString(response.getEntity()); // 用Jackson或其他工具解析responseBody为TokenDtoResponse
内容的提问来源于stack exchange,提问作者Jesús Moncada Ramírez
相关产品推荐
相关产品推荐

