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

Keycloak自定义User Storage SPI连接PostgreSQL驱动报错排查

Keycloak自定义用户联邦提供程序连接PostgreSQL驱动缺失问题

问题描述

此前已实现基于属性文件的Keycloak自定义用户联邦提供程序且运行正常,修改代码连接外部PostgreSQL用户数据库后,出现初始化错误:

Failed to init CustomProviderFactory: java.sql.SQLException: No suitable driver found for jdbc:postgresql://postgres:5432/users_db

部署环境

  • 用Docker Compose部署PostgreSQL容器,主机名为postgres,同一网络下其他容器可通过该主机名正常连接(排除网络问题)。
  • Keycloak使用自定义镜像,Dockerfile如下:
FROM quay.io/keycloak/keycloak:latest as builder

# Install custom providers
COPY target/custom-user-provider.jar /opt/keycloak/providers
RUN /opt/keycloak/bin/kc.sh build

FROM quay.io/keycloak/keycloak:latest
COPY --from=builder /opt/keycloak/ /opt/keycloak/
WORKDIR /opt/keycloak
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]

相关代码片段

CustomUserProviderFactory.java

public class CustomUserProviderFactory implements UserStorageProviderFactory<CustomUserProvider> {
    public static final String PROVIDER_NAME = "custom-user-storage";
    private static final Logger logger = Logger.getLogger(CustomUserProviderFactory.class);

    protected UserRepository userRepository;

    @Override
    public void init(Config.Scope config) {
        try {
            userRepository = new UserRepository();
            logger.error("Loaded users database");
        } catch (SQLException ex) {
            logger.error("Failed to init CustomProviderFactory", ex);
        }

    }

    @Override
    public CustomUserProvider create(KeycloakSession session, ComponentModel model) {
        return new CustomUserProvider(session, model, userRepository);
    }

    @Override
    public String getId() {
        return PROVIDER_NAME;
    }
}

UserRepository.java

public class UserRepository {
    private static final Logger logger = Logger.getLogger(UserRepository.class);

    private final static String url = "jdbc:postgresql://postgres:5432/users_db";
    private final static String username = "user";
    private final static String password = "password";
    private final Connection conn;

    public UserRepository() throws SQLException {
        // Error is thrown here
        conn = DriverManager.getConnection(url, username, password);
    }

    public User getByEmail(String email) throws SQLException {
      // Query user from DB
    }
}

问题症结:怀疑pom.xml中org.postgresql:postgresql:42.4.2依赖配置或JAR打包方式有误,尝试过多种打包方式但不确定正确性。


解决方案

1. 用Maven Shade插件构建含依赖的胖JAR

Keycloak的Provider需要JDBC驱动存在于类路径中,通过Shade插件将PostgreSQL驱动打包进自定义Provider JAR:

修改pom.xml添加插件配置:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.4.1</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <!-- SPI无需主类,留空即可 -->
                            </transformer>
                        </transformers>
                        <filters>
                            <filter>
                                <artifact>*:*</artifact>
                                <excludes>
                                    <!-- 排除签名文件避免冲突 -->
                                    <exclude>META-INF/*.SF</exclude>
                                    <exclude>META-INF/*.DSA</exclude>
                                    <exclude>META-INF/*.RSA</exclude>
                                </excludes>
                            </filter>
                        </filters>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

同时确保PostgreSQL依赖为compile scope(默认即为该值):

<dependencies>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.4.2</version>
    </dependency>
    <!-- Keycloak SPI依赖设为provided,避免重复打包 -->
    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-core</artifactId>
        <version>${keycloak.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-server-spi</artifactId>
        <version>${keycloak.version}</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

2. 显式加载PostgreSQL驱动

在UserRepository构造方法中手动加载驱动类,避免DriverManager自动发现失败:

public UserRepository() throws SQLException, ClassNotFoundException {
    // 显式加载PostgreSQL驱动
    Class.forName("org.postgresql.Driver");
    conn = DriverManager.getConnection(url, username, password);
}

3. 验证JAR包内容

构建完成后,解压target/custom-user-provider.jar,检查是否包含org/postgresql目录下的驱动类,确认驱动已被正确打包。

4. 替代方案:直接将驱动放入Keycloak lib目录

若打包胖JAR有问题,可直接将PostgreSQL驱动JAR复制到Keycloak容器的/opt/keycloak/lib目录,修改Dockerfile:

FROM quay.io/keycloak/keycloak:latest as builder

# 复制自定义Provider和PostgreSQL驱动
COPY target/custom-user-provider.jar /opt/keycloak/providers
COPY path/to/postgresql-42.4.2.jar /opt/keycloak/lib
RUN /opt/keycloak/bin/kc.sh build

FROM quay.io/keycloak/keycloak:latest
COPY --from=builder /opt/keycloak/ /opt/keycloak/
WORKDIR /opt/keycloak
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]

额外注意事项

  • 确保Keycloak版本与SPI依赖版本一致,避免兼容性问题。
  • 建议使用连接池(如HikariCP)管理数据库连接,不要在init方法中提前创建连接,避免资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 12:54:20