Keycloak 统一身份认证实战:SSO 单点登录部署配置

Keycloak 单点登录(SSO)部署是企业统一身份认证的基础设施建设。随着内部系统增多,每套系统独立维护账号密码会放大弱口令与凭证泄露风险。Keycloak 作为开源 IAM 平台,通过 OIDC/SAML 协议让用户登录一次即可访问全部接入应用,同时提供 MFA、会话策略等安全能力。本教程演示完整部署与接入流程。

适用场景

  • 企业存在多套 Web 应用,需要统一登录入口与账号体系
  • 需要为第三方应用提供 OIDC 或 SAML 身份认证
  • 需要对不同角色用户实施差异化访问控制
  • 需要集中管理密码策略、会话超时与多因素认证

前置条件

  • 一台 Linux 服务器(建议 2C4G 以上),安装 Docker 与 Docker Compose
  • 已规划域名并配置 DNS 解析,如 sso.example.com
  • 已有 TLS 证书(Keycloak 生产环境要求 HTTPS)
  • 了解 OIDC 基本概念:Client、Realm、Access Token

原理说明

Keycloak 的核心概念是 Realm(领域),一个 Realm 相当于一个独立的租户,包含用户、客户端与角色。应用作为 Client 注册到 Realm 中,用户访问应用时被重定向到 Keycloak 登录页,认证成功后 Keycloak 签发 ID Token 与 Access Token,应用通过 JWKS 公钥验签即可信任用户身份。相比每个应用各自实现登录,SSO 将认证逻辑收敛到单一平台,便于统一实施密码策略、MFA 与审计。

操作步骤

步骤一:Docker Compose 部署 Keycloak

创建 docker-compose.yml

version: "3.8"
services:
  keycloak:
    image: quay.io/keycloak/keycloak:24.0
    container_name: keycloak
    command: start --optimized
    environment:
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://db:5432/keycloak
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD: Kc@2026!StrongPass
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: Admin@2026!StrongPass
      KC_HOSTNAME: sso.example.com
      KC_HTTPS_CERTIFICATE_FILE: /certs/fullchain.pem
      KC_HTTPS_CERTIFICATE_KEY_FILE: /certs/privkey.pem
    ports:
      - "8443:8443"
    volumes:
      - /etc/letsencrypt/live/sso.example.com:/certs:ro
    depends_on:
      - db
  db:
    image: postgres:16
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: Kc@2026!StrongPass
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata:

启动并验证:

docker compose up -d
# 等待启动完成后访问管理控制台
curl -k -s -o /dev/null -w "%{http_code}" https://127.0.0.1:8443/realms/master

步骤二:创建 Realm 与客户端

在管理控制台 https://sso.example.com:8443 使用 admin 登录后:

  1. 点击左上角 master 下拉,选择 Create realm,名称填写 corp,点击 Create
  2. 进入 Clients,点击 Create client,Client ID 填写 erp-web,Client type 选择 OpenID Connect
  3. 在 Capability config 中勾选 Standard flow(授权码模式),Redirect URIs 填写 https://erp.example.com/callback
  4. 保存后切换到 Credentials 页,复制 Client secret 备用

步骤三:创建测试用户与角色

# 通过 Admin REST API 创建用户(替换 TOKEN 为客户端凭证获取的访问令牌)
curl -X POST "https://sso.example.com:8443/admin/realms/corp/users" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"username":"zhangsan","enabled":true,"email":"zhangsan@example.com","credentials":[{"type":"password","value":"User@2026!","temporary":false}]}'

同时可在管理界面 Realm roles 中创建 erp-admin 角色,并在用户详情中为用户分配该角色。

步骤四:应用侧接入 OIDC

以常见的前端接入为例,使用 oidc-client-js 初始化:

import { UserManager } from "oidc-client-ts";

const mgr = new UserManager({
  authority: "https://sso.example.com:8443/realms/corp",
  client_id: "erp-web",
  client_secret: "你的ClientSecret",
  redirect_uri: "https://erp.example.com/callback",
  response_type: "code",
  scope: "openid profile email",
});

// 触发登录跳转
mgr.signinRedirect();
// 回调页完成令牌换取
mgr.signinRedirectCallback().then(user => {
  console.log("登录用户:", user.profile.preferred_username);
});

配置验证

# 验证 Realm 公开配置可访问(OIDC 发现端点)
curl -s https://sso.example.com:8443/realms/corp/.well-known/openid-configuration | python3 -m json.tool | head -20
# 验证 JWKS 公钥端点可正常返回
curl -s -o /dev/null -w "%{http_code}" https://sso.example.com:8443/realms/corp/protocol/openid-connect/certs
# 未登录访问受保护应用应被重定向到 Keycloak 登录页
curl -s -o /dev/null -w "%{redirect_url}" http://erp.example.com/

常见问题

FAQ 1:客户端获取令牌时提示 invalid_client?

通常原因是 Client secret 不匹配或客户端未启用相应流程。检查 Clients → erp-web → Credentials 中的 secret 是否与代码一致,并在 Client authentication 处确认已开启。若是公开客户端(无 secret),则不能配置 client_secret。

FAQ 2:Keycloak 生产环境如何避免默认管理员风险?

建议:创建独立的 Realm 管理员而非直接使用 master 域 admin;为 admin 开启 MFA(Authentication → Required actions → Configure OTP);将管理控制台仅绑定内网地址或用防火墙限制来源 IP。定期检查 Realm 的会话数与异常登录日志。

总结

Keycloak 将企业身份认证收敛为单点登录统一入口,通过 Realm 隔离租户、Client 接入应用、角色控制权限,配合 OIDC 标准协议实现与任意语言的集成。生产部署务必使用 HTTPS、强密码并启用 MFA,同时做好 PostgreSQL 数据备份。接入新应用时遵循「最小权限」原则,仅分配必要的 scope 与角色,可显著降低凭证泄露与横向移动风险。