Keycloak(CNCF Incubating,WildFly/Quarkus 双运行时)是当前自建 IAM 平台最主流的选择。它实现了 OIDC、SAML 2.0、OAuth 2.0 的完整协议栈,附带用户管理、角色管理、身份联合(User Federation)和社交登录等全套功能。
但 Keycloak 的文档偏向”怎么用”(Admin Console 的操作步骤),而不是”怎么想”(内部架构和扩展设计)。本文从工程视角拆解 Keycloak 的四个核心概念和扩展机制。
一、Realm:Keycloak 的隔离单元
Realm 是 Keycloak 的顶级命名空间——一个 Realm 内的用户、Client、角色和认证流与其他 Realm 完全隔离。可以把 Realm 理解为”一个独立的 IdP 实例”(但在同一个进程中)。
flowchart TD
subgraph "Keycloak Server"
subgraph "Realm: Company A"
Users-A["Users"]
Clients-A["Clients"]
Roles-A["Roles"]
Flows-A["Auth Flows"]
end
subgraph "Realm: Company B"
Users-B["Users"]
Clients-B["Clients"]
Roles-B["Roles"]
Flows-B["Auth Flows"]
end
Master["Master Realm<br/>(管理所有其他 Realm)"]
end
Realm 的使用策略:
- 每个环境一个
Realm:
dev-realm、staging-realm、prod-realm。这比”每个环境部署一个新的 Keycloak 实例”更省运维。 - B2B SaaS 多租户场景:可以为每个大客户创建一个 Realm(客户之间强隔离),也可以所有客户共享一个 Realm(节省资源,权限通过 Group/Role 隔离)。
- Master Realm:是 Keycloak 的管理 Realm——管理员在这里管理其他 Realm。生产环境必须为 Master Realm 的管理员启用 MFA。
工程陷阱 1:Realm 的隔离不意味着性能隔离。所有 Realm 共享同一个数据库连接池和 JVM 堆。一个大 Realm 的高负载(如某企业客户在上班高峰期的集中登录)会影响其他 Realm 的延迟。
二、Authentication Flow:认证流程引擎
Keycloak 的认证不是硬编码的”密码→MFA→通过”顺序。它使用了一套 Authentication Flow 引擎——管理员可以在 Admin Console 中拖拽”认证执行器”(Authenticator)自由编排认证流程。
2.1 Flow 的结构
一个 Authentication Flow 是由三个基本结构组成的树:
| 结构 | 语义 |
|---|---|
| Execution | 一个具体的 Authenticator 执行(“验证密码”“发送 OTP”“检查 Cookie”) |
| Alternative Sub-flow | 子流程中的任一执行成功即可(如”密码 或 WebAuthn 或 社交登录”) |
| Required Sub-flow | 子流程中的所有执行都必须成功(如”密码 和 MFA”) |
2.2 内置 Authenticator
Keycloak 提供了 30+ 内置 Authenticator,覆盖了绝大多数认证场景:
| Authenticator | 作用 |
|---|---|
Cookie |
检查 Keycloak 自己的 Session Cookie——如果已有有效会话,跳过整个认证流程 |
Username Password Form |
展示用户名/密码表单 |
OTP Form |
TOTP 验证码 |
WebAuthn Authenticator |
WebAuthn/Passkey 注册和认证 |
Conditional OTP |
条件性要求 OTP——用户已配置 OTP 才触发 |
IdP Redirector |
重定向到配置的身份联合提供商(如 Azure AD, Google) |
Identity Provider Authenticator |
处理从 IdP 回来的 SAML/OIDC 断言 |
Reset Credentials |
密码重置流程 |
2.3 条件认证
Keycloak 的条件认证(Conditional Authenticator)在 18.x 引入,允许基于用户属性和上下文动态选择认证方式:
Flow: Browser Login
├── Cookie (Required)
├── Username Password Form (Required)
└── Conditional OTP (Conditional)
├── Condition: User Configured OTP = true
└── OTP Form (Required)
如果用户没有配置 OTP,条件分支直接跳过——用户密码登录后直接完成。没有条件机制的话,每个用户都必须配置 OTP(或者每个客户端需要配置不同的 Flow)。
三、Client Scope 与 Protocol Mapper
Client Scope 和 Protocol Mapper 是 Keycloak 中最容易被误解的两个概念。
Protocol
Mapper:定义”把用户的什么属性(username、email、group
等),映射到 token(ID Token、Access Token)的哪个
claim”。例如:User Attribute (department) → ID Token claim (department)。
Client Scope:一组 Protocol Mapper 的集合。可以为每个 Client 分配不同的 Client Scope,从而控制不同 Client 拿到的 token 中包含哪些 claims。
flowchart LR
UserAttr1["User Attributes<br/>(email, department, groups)"]
Mapper1["Protocol Mapper<br/>email → email claim"]
Mapper2["Protocol Mapper<br/>department → department claim"]
Mapper3["Protocol Mapper<br/>groups → groups claim"]
Scope1["Client Scope: profile<br/>(email, department)"]
Scope2["Client Scope: permissions<br/>(groups)"]
Mapper1 --> Scope1
Mapper2 --> Scope1
Mapper3 --> Scope2
Scope1 --> ClientA["Client A: 基础 OIDC App"]
Scope2 --> ClientB["Client B: 权限系统 (需要 groups)"]
工程最佳实践:为不同类型的客户端创建不同的 Client Scope——内部 Admin Console 比客户端的 App 需要更丰富的 claims。把
roles和groups的 mapper 放在 scope 中分配给需要它们的客户端,避免每个客户端的 token 都携带数以百计的 group。
四、User Federation:接外部用户源
Keycloak 的 User Federation(用户联合)允许它不存储用户数据,而是从外部用户源(LDAP、Active Directory、自定义数据库)实时查询或同步用户。
核心接口是 UserStorageProvider SPI:
public interface UserStorageProvider extends Provider {
UserModel getUserById(String id, RealmModel realm);
UserModel getUserByUsername(String username, RealmModel realm);
UserModel getUserByEmail(String email, RealmModel realm);
// ...
}Keycloak 在收到认证请求时: 1. 先查自己的本地用户表。 2. 如果找不到,按配置的 User Federation Provider 优先级依次查询。 3. 如果外部 Provider 返回用户信息,Keycloak 可以将该用户的必要属性缓存到本地数据库(“Import” 模式),减少对上游系统的压力。
工程陷阱 2:User Federation 不等于”Keycloak 内部的用户表变成了外部数据库的视图”。外部 Provider 的用户仍然在 Keycloak 内部有一个”联邦链接”(Federated Identity Link)记录。如果外部系统的用户 ID 不可变(如 AD 的
objectGUID),这个链接是稳定的。如果外部系统的用户标识会变化(如基于姓名生成的用户 ID),链接会断裂。
五、SPI 扩展:自定义一切
Keycloak 的几乎所有组件都通过 SPI(Service Provider Interface)暴露扩展点。最常用的四个:
| SPI | 用途 | 典型场景 |
|---|---|---|
Authenticator |
自定义认证执行器 | 短信验证码、微信扫码登录、自定义 MFA 方案 |
UserStorageProvider |
对接外部用户源 | 对接企业 AD/LDAP、HR 系统 |
RequiredActionProvider |
自定义”必须做的事” | 用户首次登录后强制设置安全问题、同意使用条款 |
EventListenerProvider |
事件钩子 | 登录事件 → SIEM、密码修改 → 通知、账户锁定 → 告警 |
编写一个自定义 Authenticator 的核心步骤:
public class SmsAuthenticator implements Authenticator {
@Override
public void authenticate(AuthenticationFlowContext context) {
// 1. 生成 6 位验证码,通过短信 API 发送
String code = generateCode();
smsService.send(context.getUser().getPhoneNumber(), code);
// 2. 把 code 存入用户 session notes
context.getAuthenticationSession()
.setUserSessionNote("sms_code", code);
// 3. 显示输入表单
context.challenge(
context.form()
.setAttribute("phoneNumber", context.getUser().getPhoneNumber())
.createForm("sms-code-form.ftl")
);
}
@Override
public void action(AuthenticationFlowContext context) {
// 用户提交了表单,验证 SMS 码
String entered = context.getHttpRequest()
.getDecodedFormParameters().getFirst("sms_code");
String expected = context.getAuthenticationSession()
.getUserSessionNote("sms_code");
if (entered.equals(expected)) {
context.success(); // 认证通过
} else {
context.failureChallenge(AuthenticationFlowError.INVALID_CREDENTIALS,
context.form().setError("sms_code_invalid").createForm("sms-code-form.ftl"));
}
}
}部署方式: - JAR 部署:把包含 SPI 实现的
JAR 放到 KEYCLOAK_HOME/providers/,重启
Keycloak。 - Quarkus 优化模式:用
keycloak.conf 中的 --spi-*
参数配置自定义 Provider,通过 kc.sh build
优化启动时间。
六、小结
Keycloak 是自建 IAM 的合理起点,但其内部架构需要深入理解才能做好生产部署:
- Realm 是隔离单元,但不提供性能隔离。
- Authentication Flow 引擎提供了灵活的认证编排,条件认证是高级特性。
- Client Scope + Protocol Mapper 控制 token 中的 claims——按最小权限原则分配。
- User Federation 用于对接外部用户源,注意用户标识的稳定性。
- SPI 扩展点让 Keycloak 可以定制任何认证和用户管理行为——是生产环境必备的能力。
上一篇:API Gateway、BFF 与边界认证授权 下一篇:自建还是采购:Keycloak、Auth0、Entra、Okta 对比
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【身份与访问控制工程】IAM 全景:为什么这是高价值赛道
从 2020 年 SolarWinds 到 2024 年 Okta 支持系统泄露,身份基础设施的安全失败反复证明一件事:IAM 不是 IT 支撑系统,而是安全架构的承重墙。本文建立现代 IAM 的全景地图——从认证协议、令牌体系、权限模型到身份治理与平台选型,给出 5 个贯穿全系列的核心问题。
【身份与访问控制工程】自建还是采购:Keycloak、Auth0、Entra、Okta 对比
自建 Keycloak 省下的 license 费用,会在运维、高可用、多活、定制开发和知识积累上还回去。采购 Auth0/Okta/Entra 省下的运维成本,会在 license 账单、供应商锁定和功能黑盒上付出代价。本文不是产品推荐,而是一个工程决策框架——在什么规模、什么场景下,哪种选择的总成本(TCO)合理。
【身份与访问控制工程】企业单点登录:OIDC 与现代 SSO
OIDC 是当下企业 SSO 的事实标准,但大多数实现只用了它 20% 的规范。本文从 OIDC 核心规范出发,拆解 Authorization Code Flow + PKCE 的完整交互、ID Token 的验证规则、Discovery 与 Dynamic Registration 的互操作性机制,以及 RP-Initiated Logout 和 Session Management 的工程实现细节。
【身份与访问控制工程】SAML 还值得学吗:企业遗留 SSO 的现实世界
2026 年了,SAML 2.0 这个诞生于 2005 年的标准在 OIDC 的压力下看似日薄西山,但全球超过 70% 的企业 SaaS 产品仍然把 SAML SSO 放在 Enterprise 定价方案的第一行。本文拆解 SAML 2.0 的核心协议模型、SP-Initiated 和 IdP-Initiated 两种 SSO 流程、NameID 的选择策略、SAML Metadata 的互操作性工程,以及 SAML 和 OIDC 在实际企业客户场景中的选型逻辑。