土法炼钢兴趣小组的算法知识备份

【身份与访问控制工程】Keycloak 工程拆解:Realm、Client、Flow 与扩展机制

文章导航

分类入口
architecturesecurity
标签入口
#keycloak#iam#realm#authentication-flow#spi#user-federation#openid-connect#saml

目录

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 的使用策略:

工程陷阱 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。把 rolesgroups 的 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 的合理起点,但其内部架构需要深入理解才能做好生产部署:

  1. Realm 是隔离单元,但不提供性能隔离。
  2. Authentication Flow 引擎提供了灵活的认证编排,条件认证是高级特性。
  3. Client Scope + Protocol Mapper 控制 token 中的 claims——按最小权限原则分配。
  4. User Federation 用于对接外部用户源,注意用户标识的稳定性。
  5. SPI 扩展点让 Keycloak 可以定制任何认证和用户管理行为——是生产环境必备的能力。

上一篇API Gateway、BFF 与边界认证授权 下一篇自建还是采购:Keycloak、Auth0、Entra、Okta 对比

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-06-13 · architecture / security

【身份与访问控制工程】IAM 全景:为什么这是高价值赛道

从 2020 年 SolarWinds 到 2024 年 Okta 支持系统泄露,身份基础设施的安全失败反复证明一件事:IAM 不是 IT 支撑系统,而是安全架构的承重墙。本文建立现代 IAM 的全景地图——从认证协议、令牌体系、权限模型到身份治理与平台选型,给出 5 个贯穿全系列的核心问题。

2026-06-20 · architecture / security

【身份与访问控制工程】自建还是采购:Keycloak、Auth0、Entra、Okta 对比

自建 Keycloak 省下的 license 费用,会在运维、高可用、多活、定制开发和知识积累上还回去。采购 Auth0/Okta/Entra 省下的运维成本,会在 license 账单、供应商锁定和功能黑盒上付出代价。本文不是产品推荐,而是一个工程决策框架——在什么规模、什么场景下,哪种选择的总成本(TCO)合理。

2026-06-13 · architecture / security

【身份与访问控制工程】企业单点登录:OIDC 与现代 SSO

OIDC 是当下企业 SSO 的事实标准,但大多数实现只用了它 20% 的规范。本文从 OIDC 核心规范出发,拆解 Authorization Code Flow + PKCE 的完整交互、ID Token 的验证规则、Discovery 与 Dynamic Registration 的互操作性机制,以及 RP-Initiated Logout 和 Session Management 的工程实现细节。

2026-06-14 · architecture / security

【身份与访问控制工程】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 在实际企业客户场景中的选型逻辑。


By .