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

Keycloak 12升级至26时自定义Provider遇类型转换错误求助

Keycloak 12升级至26版本自定义提供者适配错误修复

问题概述

将Keycloak从12版本升级到26版本并适配自定义提供者时,出现java.lang.VerifyError错误,核心原因是javax.ws.rs与jakarta.ws.rs的API冲突,同时Resteasy版本不兼容。

错误日志

2025-01-30 15:12:45,024 ERROR [org.keycloak.events.EventBuilder] (executor-thread-1) 向keycloak-provider发送类型失败:java.lang.VerifyError: 返回类型错误
Exception Details:
  Location:
    org/jboss/resteasy/core/providerfactory/Utils.createUriBuilder()Ljavax/ws/rs/core/UriBuilder; @7: areturn
  Reason:
    当前栈帧stack[0]中的类型'org/jboss/resteasy/specimpl/ResteasyUriBuilderImpl'无法转换为方法签名中的'javax/ws/rs/core/UriBuilder'
  Current Frame:
    bci: @7
    flags: { }
    locals: { }
    stack: { 'org/jboss/resteasy/specimpl/ResteasyUriBuilderImpl' }
  Bytecode:
    0000000: bb00 2659 b700 27b0

完整堆栈跟踪

at org.jboss.resteasy.core.providerfactory.CommonProviders.processProviderContracts(CommonProviders.java:82)
at org.jboss.resteasy.core.providerfactory.ClientHelper.processProviderContracts(ClientHelper.java:104)
at org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.processProviderContracts(ResteasyProviderFactoryImpl.java:841)
at org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.registerProvider(ResteasyProviderFactoryImpl.java:829)
at org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.registerProvider(ResteasyProviderFactoryImpl.java:816)
at org.jboss.resteasy.plugins.providers.RegisterBuiltin.registerProviders(RegisterBuiltin.java:109)
at org.jboss.resteasy.plugins.providers.RegisterBuiltin.register(RegisterBuiltin.java:74)
at org.jboss.resteasy.plugins.providers.RegisterBuiltin.getClientInitializedResteasyProviderFactory(RegisterBuiltin.java:54)
at org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl.getProviderFactory(ResteasyClientBuilderImpl.java:357)
at org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl.build(ResteasyClientBuilderImpl.java:373)
at provider.SSOGeneralFederationKCAuthorization.getToken(KCAuthorization.java:27)
at provider.EventListenerProvider.asyncSearch(EventListenerProvider.java:97)
at provider.EventListenerProvider.onEvent(EventListenerProvider.java:39)
at org.keycloak.events.EventBuilder.sendNow(EventBuilder.java:262)
at org.keycloak.events.EventBuilder.send(EventBuilder.java:249)
at org.keycloak.events.EventBuilder.success(EventBuilder.java:217)
at org.keycloak.authentication.forms.RegistrationUserCreation.success(RegistrationUserCreation.java:174)
at org.keycloak.authentication.FormAuthenticationFlow.processAction(FormAuthenticationFlow.java:253)
at org.keycloak.authentication.DefaultAuthenticationFlow.processAction(DefaultAuthenticationFlow.java:128)
at org.keycloak.authentication.AuthenticationProcessor.authenticationAction(AuthenticationProcessor.java:1034)
at org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:378)
at org.keycloak.services.resources.LoginActionsService.processRegistration(LoginActionsService.java:747)
at org.keycloak.services.resources.LoginActionsService.registerRequest(LoginActionsService.java:811)
at org.keycloak.services.resources.LoginActionsService.processRegister(LoginActionsService.java:789)
at org.keycloak.services.resources.LoginActionsService$quarkusrestinvoker$processRegister_7a9f3962753907b18ff9c85418d7f9feed84dedc.invoke(Unknown Source)
at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29)
at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:141)
at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:635)
at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2516)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2495)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1521)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:842)

引发问题的方法

public static String getToken() {
    Keycloak keycloak = KeycloakBuilder
            .builder()
            .serverUrl(propertiesService.getProperty(URL_KEYCLOAK_SERVER))
            .realm(REALM_MASTER)
            .username(USERNAME_ADMIN)
            .password(PASSWORD_ADMIN)
            .clientId(CLIENT_ADMIN)
            .resteasyClient(new ResteasyClientBuilderImpl().connectionPoolSize(10).build())
            .build();
    return keycloak.tokenManager().getAccessTokenString();
}

当前pom.xml依赖

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-core</artifactId>
    <version>26.0.3</version>
    <exclusions>
        <exclusion>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-client</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-admin-client</artifactId>
    <version>26.0.4</version>
</dependency>

<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-client</artifactId>
    <version>6.2.11.Final</version>
    <exclusions>
        <exclusion>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>jakarta.ws.rs</groupId>
    <artifactId>jakarta.ws.rs-api</artifactId>
    <version>3.1.0</version>
</dependency>

<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-core</artifactId>
    <version>4.7.9.Final</version>
    <exclusions>
        <exclusion>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>

providers文件夹中的额外JAR包

  • jakarta.ws.rs-api-4.0.0.jar
  • javax.ws.rs-api-2.1.1.jar
  • json-20240303.jar
  • keycloak-admin-client-26.0.4.jar
  • resteasy-client-6.2.11.Final.jar
  • resteasy-core-4.7.9.Final.jar
  • resteasy-jackson2-provider-4.7.9.Final.jar
  • resteasy-multipart-provider-6.2.11.Final.jar
  • wildfly-client-config-1.0.1.Final.jar

修复方案

1. 核心问题分析

Keycloak 17+版本基于Quarkus,全面切换到Jakarta EE规范,不再兼容javax.ws.rs相关API。你的问题源于:

  • 混用javax.ws.rs和jakarta.ws.rs的API包,导致类加载冲突
  • Resteasy版本不兼容:4.x对应javax,6.x对应jakarta,同时引入两个版本引发类型转换错误
  • 手动添加的JAR包与依赖管理的包重复,加剧冲突

2. 步骤1:清理pom.xml依赖

修改后的pom.xml如下,统一依赖版本并移除冲突项:

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-core</artifactId>
    <version>26.0.4</version> <!-- 与admin-client版本保持一致 -->
    <exclusions>
        <exclusion>
            <groupId>*</groupId>
            <artifactId>*</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-admin-client</artifactId>
    <version>26.0.4</version>
    <!-- 自动引入兼容的Resteasy和Jakarta依赖,无需手动添加 -->
</dependency>

说明:

  • 移除所有手动添加的resteasy-client、resteasy-core、jakarta.ws.rs-api依赖,由keycloak-admin-client自动引入匹配版本
  • 确保keycloak-core和keycloak-admin-client版本完全一致
  • 排除所有不必要的传递依赖,避免冲突

3. 步骤2:清理providers文件夹中的冲突JAR

删除以下JAR包:

  • javax.ws.rs-api-2.1.1.jar(完全废弃,改用Jakarta)
  • jakarta.ws.rs-api-4.0.0.jar(版本过高,Keycloak 26对应Jakarta EE 10,适配3.1.x版本)
  • resteasy-core-4.7.9.Final.jar(与Resteasy 6.x冲突)
  • keycloak-admin-client-26.0.4.jar(由pom依赖管理,无需手动放置)
  • resteasy-jackson2-provider-4.7.9.Final.jar(版本不兼容,改用admin-client传递的版本)

保留必要的JAR:

  • json-20240303.jar
  • resteasy-client-6.2.11.Final.jar
  • resteasy-multipart-provider-6.2.11.Final.jar
  • wildfly-client-config-1.0.1.Final.jar

4. 步骤3:修正代码中的客户端创建逻辑

不要直接实例化ResteasyClientBuilderImpl,改用兼容Jakarta的API:

import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;

public static String getToken() {
    // 使用ResteasyClientBuilder而非Impl类
    ResteasyClient client = new ResteasyClientBuilder()
            .connectionPoolSize(10)
            .build();
            
    Keycloak keycloak = KeycloakBuilder
            .builder()
            .serverUrl(propertiesService.getProperty(URL_KEYCLOAK_SERVER))
            .realm(REALM_MASTER)
            .username(USERNAME_ADMIN)
            .password(PASSWORD_ADMIN)
            .clientId(CLIENT_ADMIN)
            .resteasyClient(client)
            .build();
            
    return keycloak.tokenManager().getAccessTokenString();
}

或者更简单,直接使用Keycloak默认客户端(无需手动创建):

public static String getToken() {
    Keycloak keycloak = KeycloakBuilder
            .builder()
            .serverUrl(propertiesService.getProperty(URL_KEYCLOAK_SERVER))
            .realm(REALM_MASTER)
            .username(USERNAME_ADMIN)
            .password(PASSWORD_ADMIN)
            .clientId(CLIENT_ADMIN)
            .build();
            
    return keycloak.tokenManager().getAccessTokenString();
}

5. 步骤4:重新构建并部署

  • 执行mvn clean install清理旧依赖并重新构建
  • 将新的提供者JAR部署到Keycloak的providers文件夹
  • 重启Keycloak服务

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 17:27:31