为 Keycloak 提供钉钉 OAuth2.0 登录集成,支持独立 JAR 热插拔部署,无需重新编译 Keycloak Docker 镜像。
| 组件 | 版本 |
|---|---|
| Keycloak | 26.0.7+ |
| Java | 17+ |
| Maven | 3.6+ |
| FastJSON2 | 2.0.52 |
| Commons Lang3 | 3.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 # 本文档
cd keycloak-dingtalk-provider
mvn clean package -DskipTests
编译成功后,JAR 文件位于:target/keycloak-dingtalk-provider.jar(约 2.5MB,包含所有依赖)
# 复制 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
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"
https://your-keycloak-domain/admin| 字段 | 说明 |
|---|---|
| Client ID | 钉钉 AppKey |
| Client Secret | 钉钉 AppSecret |
| 登录后是否更新用户信息 | 默认开启,每次登录更新用户信息 |
| 匹配失败是否允许登录 | 默认开启,匹配失败时创建新用户 |
https://your-keycloak-domain/realms/{realm}/broker/dingtalk/endpoint
Contact.User.mobile)Contact.User.Read)https://your-keycloak-domain/realms/{realm}/account用户触发登录 ↓ 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 用户
与企业微信、飞书不同,钉钉有以下特性:
| 特性 | 钉钉 | 企业微信 | 飞书 |
|---|---|---|---|
| Token 请求格式 | JSON Body | Query 参数 | Query 参数 |
| 用户信息请求头 | x-acs-dingtalk-access-token | Query 参数 | Authorization |
| 参数名 | clientId/clientSecret | appid/secret | app_id/app_secret |
| 钉钉字段 | Keycloak 属性 | 处理逻辑 |
|---|---|---|
unionId | 用户唯一ID | 优先使用,跨应用唯一 |
openId | dingtalk_openid | 应用内唯一标识 |
nick | nickname | 用户昵称 |
mobile | phoneNumber | 自动去除 +86 前缀 |
email | email | 邮箱地址 |
dt_ + 昵称dingtalk_user_ + 时间戳# 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.classcom/tencent/keycloak/dingtalk/DingTalkIdentityProviderFactory.classcom/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)
症状:在「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)"
症状:日志中出现类未找到错误
解决方案:
# 确认 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
症状:授权时钉钉返回错误
解决方案:
症状:授权后跳转失败
解决方案: 确保钉钉后台配置的回调地址与 Keycloak 生成的完全一致:
https://(生产环境)或 http://(开发环境)/realms/{realm}/broker/dingtalk/endpoint/症状:登录成功但用户属性为空
解决方案: 检查钉钉后台权限是否开通:
Contact.User.mobile)Contact.User.Read)java -version
# 应显示 openjdk version "17.x.x" 或更高
# 查找 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
# 清理本地仓库缓存
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>
# 1. 编译新版本
mvn clean package -DskipTests
# 2. 替换 JAR
docker cp target/keycloak-dingtalk-provider.jar keycloak:/opt/keycloak/providers/
# 3. 重启
docker restart keycloak
# 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
使用 HTTPS
KC_HTTPS_CERTIFICATE_FILE=/path/to/cert.pem KC_HTTPS_CERTIFICATE_KEY_FILE=/path/to/key.pem
定期轮换密钥
启用审计日志
KC_LOG_LEVEL=INFO KC_FEATURES=token-exchange,admin-fine-grained-authz
Apache License 2.0