logo
0
0
WeChat Login
feat: 添加钉钉登录集成Provider

Keycloak 钉钉登录集成 Provider

为 Keycloak 提供钉钉 OAuth2.0 登录集成,支持独立 JAR 热插拔部署,无需重新编译 Keycloak Docker 镜像。

功能特性

  • 支持钉钉 OAuth2.0 标准登录流程
  • 独立 JAR 包部署,支持热插拔
  • 自动同步用户信息(昵称、手机号、邮箱)
  • 支持企业内部应用和扫码登录两种模式
  • 兼容 Keycloak 26.0.7+

技术栈

组件版本
Keycloak26.0.7+
Java17+
Maven3.6+
FastJSON22.0.52
Commons Lang33.12.0

项目结构

keycloak-dingtalk-provider/ ├── src/main/java/com/tencent/keycloak/dingtalk/ │ ├── DingTalkIdentityProvider.java # 核心 Provider 实现 │ ├── DingTalkIdentityProviderFactory.java # Factory 类 │ ├── UserDto.java # 用户信息 DTO │ └── UserTokenDto.java # Token 响应 DTO ├── src/main/resources/META-INF/services/ │ └── org.keycloak.broker.social.SocialIdentityProviderFactory # SPI 注册 ├── pom.xml # Maven 配置 └── README.md # 本文档

快速开始

前置要求

  • Keycloak 26.0.7+ 正在运行(Docker 或本地安装)
  • Java 17+
  • Maven 3.6+
  • 钉钉开放平台账号

Step 1: 编译打包

cd keycloak-dingtalk-provider mvn clean package -DskipTests

编译成功后,JAR 文件位于:target/keycloak-dingtalk-provider.jar(约 2.5MB,包含所有依赖)

Step 2: 部署到 Keycloak

Docker 容器部署

# 复制 JAR 到容器 docker cp target/keycloak-dingtalk-provider.jar keycloak:/opt/keycloak/providers/ # 重启容器 docker restart keycloak

本地安装部署

# 复制 JAR 到 providers 目录 cp target/keycloak-dingtalk-provider.jar /path/to/keycloak/providers/ # 重新构建并重启 /path/to/keycloak/bin/kc.sh build /path/to/keycloak/bin/kc.sh start

Docker Compose 挂载

version: '3' services: keycloak: image: keycloak/keycloak:26.0.7 volumes: - ./target/keycloak-dingtalk-provider.jar:/opt/keycloak/providers/keycloak-dingtalk-provider.jar:ro environment: KEYCLOAK_ADMIN: admin KEYCLOAK_ADMIN_PASSWORD: admin command: start-dev ports: - "8080:8080"

Step 3: 配置 Keycloak

  1. 登录 Keycloak 管理控制台:https://your-keycloak-domain/admin
  2. 选择 Realm → Identity ProvidersAdd provider
  3. 在下拉列表中选择「钉钉
  4. 填写配置:
字段说明
Client ID钉钉 AppKey
Client Secret钉钉 AppSecret
登录后是否更新用户信息默认开启,每次登录更新用户信息
匹配失败是否允许登录默认开启,匹配失败时创建新用户
  1. 保存后,复制生成的「Redirect URI」:
    https://your-keycloak-domain/realms/{realm}/broker/dingtalk/endpoint

Step 4: 配置钉钉开放平台

  1. 访问 钉钉开放平台 → 创建「企业内部应用」
  2. 记录凭证:
    • 应用信息凭证与基础信息
    • 记录 AppKey(作为 Client ID)
    • 记录 AppSecret(作为 Client Secret)
  3. 配置回调地址:
    • 开发配置安全设置重定向URL
    • 添加从 Keycloak 复制的回调地址
  4. 开通权限(开发配置权限管理):
    • ✅ 个人手机号信息 (Contact.User.mobile)
    • ✅ 通讯录个人信息读权限 (Contact.User.Read)
  5. 发布应用:应用发布版本管理与发布 → 点击发布

Step 5: 测试登录

  1. 访问登录页面:https://your-keycloak-domain/realms/{realm}/account
  2. 点击「钉钉登录」按钮
  3. 扫码或输入账号授权
  4. 授权后自动返回 Keycloak

技术实现

OAuth2.0 流程

用户触发登录 ↓ 1. 构造授权 URL https://login.dingtalk.com/oauth2/auth ↓ 2. 用户授权并回调(携带 code 参数) ↓ 3. 换取 access_token POST https://api.dingtalk.com/v1.0/oauth2/userAccessToken Content-Type: application/json Body: {"clientId": "xxx", "clientSecret": "xxx", "code": "xxx", "grantType": "authorization_code"} ↓ 4. 获取用户信息 GET https://api.dingtalk.com/v1.0/contact/users/me Header: x-acs-dingtalk-access-token: <token> ↓ 5. 创建/更新 Keycloak 用户

钉钉 API 特性

与企业微信、飞书不同,钉钉有以下特性:

特性钉钉企业微信飞书
Token 请求格式JSON BodyQuery 参数Query 参数
用户信息请求头x-acs-dingtalk-access-tokenQuery 参数Authorization
参数名clientId/clientSecretappid/secretapp_id/app_secret

用户属性映射

钉钉字段Keycloak 属性处理逻辑
unionId用户唯一ID优先使用,跨应用唯一
openIddingtalk_openid应用内唯一标识
nicknickname用户昵称
mobilephoneNumber自动去除 +86 前缀
emailemail邮箱地址

用户名生成规则

  • 格式:dt_ + 昵称
  • 特殊字符会被替换为下划线
  • 若无昵称:dingtalk_user_ + 时间戳

验证部署

检查 JAR 文件

# Docker 容器 docker exec keycloak ls -lh /opt/keycloak/providers/keycloak-dingtalk-provider.jar # 检查 JAR 内容 jar tf target/keycloak-dingtalk-provider.jar | grep -E "(DingTalk|fastjson|commons-lang)"

预期输出应包含:

  • com/tencent/keycloak/dingtalk/DingTalkIdentityProvider.class
  • com/tencent/keycloak/dingtalk/DingTalkIdentityProviderFactory.class
  • com/alibaba/fastjson2/...
  • org/apache/commons/lang3/...

检查日志

# Docker 容器 docker logs keycloak 2>&1 | grep -i dingtalk

预期输出:

INFO [org.keycloak.services] (main) KC-SERVICES0050: Initializing provider dingtalk INFO [org.keycloak.services] (main) KC-SERVICES0051: Loaded SPI social (provider = dingtalk)

验证管理控制台

  1. 登录 Keycloak Admin Console
  2. 选择 Realm → Identity Providers → Add provider
  3. 确认下拉列表中存在「钉钉」选项

故障排查

问题 1: Provider 未出现

症状:在「Add provider」下拉列表中找不到「钉钉」

解决方案

# 1. 检查 JAR 是否存在 docker exec keycloak ls -lh /opt/keycloak/providers/keycloak-dingtalk-provider.jar # 2. 强制重建 docker exec keycloak /opt/keycloak/bin/kc.sh build --verbose # 3. 重启容器 docker restart keycloak # 4. 查看启动日志 docker logs keycloak 2>&1 | grep -E "(dingtalk|SPI|provider)"

问题 2: ClassNotFoundException

症状:日志中出现类未找到错误

解决方案

# 确认 JAR 包含所有依赖 jar tf target/keycloak-dingtalk-provider.jar | grep -E "(fastjson|commons-lang)" # 如果缺失,重新打包 mvn clean package -DskipTests # 确认 JAR 大小 > 2MB(包含依赖) ls -lh target/keycloak-dingtalk-provider.jar

问题 3: OAuth 错误 "invalid_client"

症状:授权时钉钉返回错误

解决方案

  1. 检查钉钉后台的 AppKey 和 AppSecret
  2. 确保没有多余的空格
  3. 重新配置 Keycloak IDP

问题 4: 回调地址错误 "redirect_uri_mismatch"

症状:授权后跳转失败

解决方案: 确保钉钉后台配置的回调地址与 Keycloak 生成的完全一致

  • ✅ 协议:https://(生产环境)或 http://(开发环境)
  • ✅ 域名:必须完全匹配
  • ✅ 路径:/realms/{realm}/broker/dingtalk/endpoint
  • ❌ 末尾不要加多余的 /

问题 5: 用户信息未同步

症状:登录成功但用户属性为空

解决方案: 检查钉钉后台权限是否开通:

  • ✅ 个人手机号信息 (Contact.User.mobile)
  • ✅ 通讯录个人信息读权限 (Contact.User.Read)

编译说明

环境配置

检查 Java 版本

java -version # 应显示 openjdk version "17.x.x" 或更高

配置 JAVA_HOME(macOS/Linux)

# 查找 Java 安装路径 /usr/libexec/java_home -V # 设置 JAVA_HOME export JAVA_HOME=$(/usr/libexec/java_home -v 17) # 永久配置(添加到 ~/.zshrc 或 ~/.bash_profile) echo 'export JAVA_HOME=$(/usr/libexec/java_home -v 17)' >> ~/.zshrc source ~/.zshrc

编译命令

# 完整编译(推荐) mvn clean package -DskipTests # 仅编译不打包 mvn clean compile # 并行编译(加速) mvn -T 4 clean package -DskipTests # 离线模式(依赖已下载后) mvn clean package -o -DskipTests

常见编译问题

Maven 依赖下载失败

# 清理本地仓库缓存 rm -rf ~/.m2/repository/com/alibaba/fastjson2 # 重新下载 mvn clean install -U # 或使用国内镜像(编辑 ~/.m2/settings.xml)
<mirrors> <mirror> <id>aliyun</id> <mirrorOf>central</mirrorOf> <url>https://maven.aliyun.com/repository/public</url> </mirror> </mirrors>

更新与卸载

更新 Provider

# 1. 编译新版本 mvn clean package -DskipTests # 2. 替换 JAR docker cp target/keycloak-dingtalk-provider.jar keycloak:/opt/keycloak/providers/ # 3. 重启 docker restart keycloak

卸载 Provider

# 1. 删除 JAR docker exec keycloak rm /opt/keycloak/providers/keycloak-dingtalk-provider.jar # 2. 重建 docker exec keycloak /opt/keycloak/bin/kc.sh build # 3. 重启 docker restart keycloak # 4. 在管理控制台删除 IDP 配置 # Identity Providers → dingtalk → Delete

生产环境建议

安全加固

  1. 使用 HTTPS

    KC_HTTPS_CERTIFICATE_FILE=/path/to/cert.pem KC_HTTPS_CERTIFICATE_KEY_FILE=/path/to/key.pem
  2. 定期轮换密钥

    • 每 90 天更新 AppSecret
    • 在钉钉后台和 Keycloak 同步更新
  3. 启用审计日志

    KC_LOG_LEVEL=INFO KC_FEATURES=token-exchange,admin-fine-grained-authz

性能特性

  • JAR 大小:约 2.5MB(包含所有依赖)
  • 编译时间:约 30 秒
  • 部署时间:< 5 秒
  • Provider 加载:< 1 秒

参考资源


许可证

Apache License 2.0