本文介绍如何在 Quarkus 框架中集成 OIDC 认证和 Hibernate ORM,实现多租户数据源配置和身份认证功能。

参考资料:Quarkus 官方文档

Quarkus 简介

Quarkus 是专为 OpenJDK HotSpot 和 GraalVM 量身定制的 Kubernetes 原生 Java 技术栈,采用最佳 Java 库和标准精心打造。它具有以下特点:

  • 快速启动:采用编译时启动技术,实现惊人的快速启动时间
  • 低内存占用:极低的 RSS 内存占用(不仅是堆大小)
  • 云原生优化:在 Kubernetes 等容器编排平台中提供近乎即时的向上扩展和高密度内存利用率
  • 响应式编程:支持 JDK 9+ 的 Publisher/Flow 响应式编程模型
  • 开源协议:所有依赖项都基于 Apache Software License 2.0

官方提供了多个性能对比示例:https://quarkus.io/vision/continuum

环境准备

基础要求

  • JDK:9 或以上版本
  • Maven:3.6.2 或以上版本
  • IDE:IntelliJ IDEA(推荐)

IDE 插件安装

在 IDEA 中安装 Quarkus 相关插件:

  1. 打开 IDEA 的插件市场
  2. 搜索并安装 Quarkus ToolsQuarkus Integration
  3. 重启 IDE 使插件生效

安装完插件后,创建 Quarkus 项目与 Spring Boot 类似。如果创建失败,可以访问 https://code.quarkus.io/ 手动创建项目(类似 Spring Initializr)。

更多使用指南可参考:https://quarkus.io/guides/

OIDC 认证集成

添加依赖

pom.xml 中添加 OIDC 扩展:

1
2
3
4
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc</artifactId>
</dependency>

自定义认证信息增强器

创建 RolesAugmentor 类,用于在认证过程中增强用户角色和权限信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import io.quarkus.security.identity.AuthenticationRequestContext;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.identity.SecurityIdentityAugmentor;
import io.quarkus.security.runtime.QuarkusSecurityIdentity;
import io.smallrye.mutiny.Uni;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.microprofile.jwt.JsonWebToken;

import javax.enterprise.context.ApplicationScoped;
import java.util.*;
import java.util.function.Supplier;

@Slf4j
@ApplicationScoped
public class RolesAugmentor implements SecurityIdentityAugmentor, Supplier<SecurityIdentity> {

SecurityIdentity identity;

@Override
public int priority() {
return 0;
}

@Override
public Uni<SecurityIdentity> augment(SecurityIdentity securityIdentity,
AuthenticationRequestContext authenticationRequestContext) {
this.identity = securityIdentity;
return authenticationRequestContext.runBlocking(this::get);
}

@Override
public SecurityIdentity get() {
if (!identity.isAnonymous()) {
// 获取用户角色
Set<String> roles = identity.getRoles();

// 根据角色从数据库查询权限
Set<String> permissions = new HashSet<>();
// TODO: 查询数据库获取权限
// permissions = permissionRepository.findByRoles(roles);

// 获取客户端信息
Map<String, Object> clientInfo = ((JsonWebToken) identity.getPrincipal())
.getClaim("client-id");

// 构建增强后的安全身份
return QuarkusSecurityIdentity.builder()
.setPrincipal(identity.getPrincipal())
.addAttributes(clientInfo == null ? Collections.emptyMap() : clientInfo)
.addCredentials(identity.getCredentials())
.addRoles(permissions)
.build();
}

return identity;
}
}

实现多租户解析器

创建 CustomTenantResolver 类,根据请求路径动态解析租户信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import io.quarkus.oidc.TenantResolver;
import io.vertx.ext.web.RoutingContext;

import javax.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class CustomTenantResolver implements TenantResolver {

@Override
public String resolve(RoutingContext context) {
String path = context.request().path();
String[] parts = path.split("/");

if (parts.length == 0) {
// 解析为默认租户配置
return "default";
}

// 根据 URL 第一段确定租户
return parts[1];
}
}

Hibernate ORM 集成

添加依赖

pom.xml 中添加 Hibernate ORM 和数据库驱动依赖:

1
2
3
4
5
6
7
8
9
10
11
<!-- Hibernate ORM -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm</artifactId>
</dependency>

<!-- PostgreSQL JDBC 驱动 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-postgresql</artifactId>
</dependency>

实现数据源租户解析器

创建 Hibernate 的租户解析器,实现多数据源切换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import io.quarkus.hibernate.orm.runtime.tenant.TenantResolver;
import io.vertx.ext.web.RoutingContext;
import org.eclipse.microprofile.config.inject.ConfigProperty;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

@ApplicationScoped
public class CustomTenantResolver implements TenantResolver {

@Inject
RoutingContext context;

@ConfigProperty(name = "quarkus.hibernate-orm.datasource")
public String defaultTenant;

@Override
public String getDefaultTenantId() {
return defaultTenant;
}

@Override
public String resolveTenantId() {
String path = context.request().path();
String[] parts = path.split("/");

if (parts.length == 0) {
// 解析为默认租户配置
return getDefaultTenantId();
}

// 根据 URL 第一段确定租户
return parts[1];
}
}

多数据源配置

Quarkus 支持多数据源配置,但需要注意:编译后的文件不支持二次修改(因为字节码增强)。

详细配置参考:Quarkus Datasource 文档

配置示例

application.propertiesapplication.yml 中配置多数据源和 OIDC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 默认数据源配置
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=username
quarkus.datasource.password=password
quarkus.datasource.jdbc.url=jdbc:postgresql://192.168.56.110:5432/default

# Hibernate 多租户配置
quarkus.hibernate-orm.multitenant=DATABASE # 可选:DATABASE(多库)或 SCHEMA(多模式)
quarkus.hibernate-orm.dialect=org.hibernate.dialect.PostgreSQL10Dialect
quarkus.hibernate-orm.datasource=default
quarkus.hibernate-orm.database.generation=none # DDL 自动生成策略
quarkus.hibernate-orm.packages=org.xiaowu

# OIDC 默认配置
quarkus.oidc.auth-server-url=http://192.168.56.110:8080/auth/realms/default
quarkus.oidc.client-id=service
quarkus.oidc.credentials.secret=secret

# 租户 default 配置
quarkus.datasource.default.db-kind=${quarkus.datasource.db-kind}
quarkus.datasource.default.username=${quarkus.datasource.username}
quarkus.datasource.default.password=${quarkus.datasource.password}
quarkus.datasource.default.jdbc.url=${quarkus.datasource.jdbc.url}
quarkus.oidc."default".auth-server-url=${quarkus.oidc.auth-server-url}
quarkus.oidc."default".client-id=${quarkus.oidc.client-id}
quarkus.oidc."default".credentials.secret=${quarkus.oidc.credentials.secret}

# 租户 A 配置
quarkus.datasource.A.db-kind=postgresql
quarkus.datasource.A.username=username
quarkus.datasource.A.password=password
quarkus.datasource.A.jdbc.url=jdbc:postgresql://192.168.56.110:5432/A
quarkus.oidc.A.auth-server-url=http://192.168.56.110:8080/auth/realms/A
quarkus.oidc.A.client-id=backend-service
quarkus.oidc.A.credentials.secret=secret

使用建议

  1. 租户隔离策略:根据业务需求选择数据库级别(DATABASE)或模式级别(SCHEMA)的多租户隔离
  2. 性能优化:合理配置连接池大小和超时时间
  3. 安全性:生产环境务必使用环境变量或密钥管理服务存储敏感信息
  4. 监控告警:集成 Quarkus 的健康检查和指标监控

总结

通过集成 OIDC 和 Hibernate,Quarkus 可以轻松实现:

  • 基于标准的身份认证和授权
  • 灵活的多租户数据源管理
  • 高性能的云原生应用部署

结合 Quarkus 的快速启动和低内存占用特性,非常适合构建现代化的微服务应用。