2. Development 环境搭建:本地 Keycloak/Dex 容器部署、HTTPS 自签名证书配置、客户端注册

在 OIDC 异步任务调试中,Development 环境是验证流程正确性的第一道防线。本章将指导你使用 Docker Compose 在本地快速搭建 Keycloak 和 Dex 两套 OIDC 提供者,配置 HTTPS 自签名证书,并完成客户端注册。所有操作均面向异步调试场景,确保后续章节的 Token 颁发、刷新、撤销流程可复现。

2.1 环境概览与组件选择

Development 环境需要模拟生产级 OIDC 流程,但降低复杂度。我们选择两套主流 OIDC 实现:

组件 角色 端口 适用场景
Keycloak 全功能 OIDC/OAuth2 提供者 8443 (HTTPS) 标准授权码流程、客户端认证、异步 Token 刷新
Dex 轻量级 OIDC 连接器 5556 (HTTPS) 多后端身份代理、异步 Token 交换、测试环境快速启动
自签名 CA 本地信任锚点 — 为所有容器签发 TLS 证书,避免浏览器/客户端证书错误
异步调试要点: 本地环境使用自签名证书时,异步 HTTP 客户端(如 aiohttp、httpx)需要显式设置 verify=False 或加载 CA 证书。后续章节的异步任务排错将依赖此配置。

2.2 自签名证书体系搭建

使用 OpenSSL 创建本地 CA 并为 Keycloak 和 Dex 签发证书。所有证书存放在 ./certs/ 目录。

# 1. 创建 CA 私钥和自签名根证书
mkdir -p ./certs
openssl genrsa -out ./certs/ca.key 4096
openssl req -x509 -new -nodes -key ./certs/ca.key \
  -sha256 -days 3650 \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=DevOIDC/CN=DevCA" \
  -out ./certs/ca.crt

# 2. 为 Keycloak 生成私钥和 CSR
openssl genrsa -out ./certs/keycloak.key 2048
openssl req -new -key ./certs/keycloak.key \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=DevOIDC/CN=keycloak.local" \
  -out ./certs/keycloak.csr

# 3. 使用 CA 签发 Keycloak 证书(含 SAN)
cat > ./certs/keycloak.ext <<EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = keycloak.local
DNS.2 = localhost
IP.1 = 127.0.0.1
EOF

openssl x509 -req -in ./certs/keycloak.csr \
  -CA ./certs/ca.crt -CAkey ./certs/ca.key \
  -CAcreateserial -out ./certs/keycloak.crt \
  -days 365 -sha256 -extfile ./certs/keycloak.ext

# 4. 为 Dex 重复相同步骤(CN=dex.local)
openssl genrsa -out ./certs/dex.key 2048
openssl req -new -key ./certs/dex.key \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=DevOIDC/CN=dex.local" \
  -out ./certs/dex.csr
# 使用类似 keycloak.ext 的 SAN 配置,将 DNS.1 改为 dex.local
openssl x509 -req -in ./certs/dex.csr \
  -CA ./certs/ca.crt -CAkey ./certs/ca.key \
  -CAcreateserial -out ./certs/dex.crt \
  -days 365 -sha256 -extfile ./certs/dex.ext
证书信任: 将 ca.crt 导入操作系统或浏览器的受信任根证书颁发机构。否则异步请求会因 TLS 握手失败而抛出 SSLCertVerificationError,打断调试流程。

2.3 Keycloak 容器部署

使用 Docker Compose 启动 Keycloak,挂载证书并开启 HTTPS。同时配置持久化数据库以保留客户端注册信息。

# docker-compose.yml 片段(Keycloak 部分)
version: '3.8'
services:
  keycloak:
    image: quay.io/keycloak/keycloak:22.0.5
    container_name: oidc-keycloak
    command: start --optimized
    environment:
      KC_HOSTNAME: keycloak.local
      KC_HTTPS_CERTIFICATE_FILE: /certs/keycloak.crt
      KC_HTTPS_CERTIFICATE_KEY_FILE: /certs/keycloak.key
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD: keycloak_pass
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: admin
    ports:
      - "8443:8443"
    volumes:
      - ./certs:/certs:ro
    depends_on:
      - postgres

  postgres:
    image: postgres:15
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: keycloak_pass
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

启动后访问 https://keycloak.local:8443,使用 admin/admin 登录管理控制台。

2.4 Dex 容器部署

Dex 作为轻量级 OIDC 提供者,配置更简洁。使用静态客户端和本地连接器。

# docker-compose.yml 片段(Dex 部分)
  dex:
    image: ghcr.io/dexidp/dex:v2.37.0
    container_name: oidc-dex
    command: dex serve /etc/dex/config.yaml
    ports:
      - "5556:5556"
    volumes:
      - ./certs:/certs:ro
      - ./dex-config.yaml:/etc/dex/config.yaml:ro
# dex-config.yaml
issuer: https://dex.local:5556

storage:
  type: sqlite3
  config:
    file: /var/dex/dex.db

web:
  https: 0.0.0.0:5556
  tlsCert: /certs/dex.crt
  tlsKey: /certs/dex.key

staticClients:
  - id: dev-client
    redirectURIs:
      - 'https://oidcdebugger.local/callback'
      - 'http://localhost:8080/callback'
    name: 'Development Client'
    secret: dev-secret

connectors:
  - type: local
    id: local
    name: Local Users
    config:
      users:
        - email: test@dev.local
          hash: $2a$10$...  # bcrypt hash of "password"
异步调试提示: Dex 的 SQLite 存储适合单机开发。若需模拟异步并发场景,可切换至 PostgreSQL 或 etcd 存储后端。

2.5 客户端注册与 OIDC 配置

在 Keycloak 管理控制台中注册一个公开客户端,用于异步授权码流程。

参数 值 说明
Client ID async-debug-client 唯一标识
Client authentication Off (公开客户端) 异步流程中避免客户端密钥泄露
Standard Flow Enabled ON 授权码流程
Valid Redirect URIs https://oidcdebugger.local/callback 异步回调地址
Web Origins + 允许 CORS

Dex 的客户端已在 staticClients 中定义,无需额外注册。两者均支持以下 OIDC 端点:

  • 授权端点: /auth (Keycloak) / /authorize (Dex)
  • Token 端点: /token (两者一致)
  • JWKS 端点: /certs (Keycloak) / /keys (Dex)
  • UserInfo 端点: /userinfo (两者一致)

2.6 环境验证与异步测试

使用 curl 验证 Token 端点可达性,并测试异步刷新流程。

# 验证 Keycloak Token 端点(使用客户端凭证模式)
curl -k --cert ./certs/ca.crt \
  -X POST "https://keycloak.local:8443/realms/master/protocol/openid-connect/token" \
  -d "client_id=async-debug-client" \
  -d "grant_type=client_credentials" \
  -d "client_secret="

# 验证 Dex Token 端点
curl -k --cert ./certs/ca.crt \
  -X POST "https://dex.local:5556/token" \
  -d "grant_type=password" \
  -d "client_id=dev-client" \
  -d "client_secret=dev-secret" \
  -d "username=test@dev.local" \
  -d "password=password"
异步调试准备: 返回的 access_token 和 refresh_token 将用于后续章节的异步任务调试。建议将 Token 保存为环境变量 OIDC_ACCESS_TOKEN 和 OIDC_REFRESH_TOKEN。

2.7 整体架构图

下图展示了 Development 环境的组件关系与 OIDC 异步流程路径。

Development 环境 OIDC 异步流程架构 Development 环境 OIDC 异步流程架构 异步客户端 Keycloak 8443 (HTTPS) Dex 5556 (HTTPS) 自签名 CA 授权码/Token 异步 Token 交换 签发 TLS 证书 签发 TLS 证书 异步调试关键路径 1. 客户端发起授权码请求 → Keycloak/Dex 返回授权码 2. 异步 Token 端点交换授权码获取 access_token + refresh_token 3. 使用 refresh_token 异步刷新 Token(无需用户交互)

2.8 常见问题与排错

问题 原因 解决方案
HTTPS 连接被拒绝 证书 SAN 不匹配或端口未映射 检查 docker-compose ps 确认容器运行;使用 openssl s_client -connect keycloak.local:8443 验证证书
Token 端点返回 401 客户端密钥错误或 grant_type 不支持 核对 Keycloak 客户端认证方式;Dex 确保 staticClients.secret 匹配
异步回调收不到授权码 Redirect URI 未注册或 HTTPS 证书不被信任 在客户端配置中添加完整回调地址;将 ca.crt 加入系统信任存储
Dex 启动失败 配置文件 YAML 格式错误或 SQLite 权限不足 使用 docker logs oidc-dex 查看错误;确保 /var/dex/ 目录可写