ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

钉钉开放平台接口API开发入门

钉钉开放平台接口API开发入门 钉钉开放平台接口API开发入门钉钉开放平台提供通讯录、审批、考勤、机器人、待办和消息通知等能力。本文以最常见的企业内部应用为例从创建应用开始介绍权限配置、凭证管理、accessToken获取、接口调用、事件订阅和 Java 接入方式。欢迎来我的博客查看本篇文章钉钉开放平台会持续调整控制台入口、接口版本和权限名称。实际开发时应以目标接口页面中的请求地址、参数和权限点为准。开发过程中可在钉钉开发者文档搜索具体能力、接口名称或错误码。一、开发前准备开始前需要具备以下条件一个完成认证的钉钉组织钉钉组织管理员或子管理员权限可登录钉钉开放平台一个可被钉钉访问的 HTTPS 服务地址Java 8 及以上环境如果使用本文的 Java 示例。常见的钉钉应用类型如下| 类型 | | 仅供本企业内部使用OA 系统集成通常选择此类型 || 第三方企业应用 | 提供给多个企业安装使用需要处理授权关系 || 小程序/H5 微应用 | 在钉钉客户端中提供交互页面 || 机器人应用 | 群消息、单聊消息和事件处理 |本文不涉及第三方应用的授权套件流程。二、创建企业内部应用1. 登录开发者后台打开钉钉开放平台进入开发者后台选择需要接入的组织。2. 创建应用依次进入应用开发 → 企业内部应用 → 创建应用填写应用名称、应用描述、应用图标等信息。创建成功后在应用详情中记录以下参数参数说明是否保密Client IDAppKey应用唯一标识否但不建议公开Client SecretAppSecret应用密钥是AgentId企业内部应用实例 ID部分消息和 JSAPI 会使用否CorpId企业 ID部分登录和前端接口会使用否Client Secret只能保存在服务端不能写入网页、H5、小程序或提交到 Git 仓库。截图用于博客发布时至少应遮盖应用名称、App ID、AgentId、Client ID 和 Client Secret。只要 Client Secret 曾经公开应立即在开发者后台重置打码不能消除此前泄露的风险。3. 配置应用可见范围在应用发布或版本管理页面设置可见范围例如指定部门或员工。即使接口权限已经开通如果用户不在应用可见范围内某些接口仍可能无法正常访问。4. 配置服务器出口 IP部分接口要求配置服务器出口 IP 白名单。应填写调用钉钉接口时实际使用的公网出口 IP而不是服务器内网 IP。如果服务部署在 NAT 网关、负载均衡或云服务器后面可先在服务器执行curlhttps://api.ipify.org然后将返回的固定公网 IP 配置到应用安全设置中。生产环境不要使用频繁变化的动态出口 IP。三、申请接口权限进入应用的权限管理页面搜索目标接口要求的权限并申请。例如读取通讯录通常需要对应的通讯录只读权限。接口是否可以成功调用通常同时受以下三项限制应用是否已经申请目标接口的权限点当前组织管理员是否已经授权应用通讯录权限范围是否包含目标部门或用户。建议先确定需要调用的接口再根据该接口文档中的权限要求按最小权限原则申请不要一次性申请无关权限。四、获取 accessToken服务端调用新版钉钉 OpenAPI 前需要先通过应用凭证换取accessToken。1. 请求信息请求方式POST 请求地址https://api.dingtalk.com/v1.0/oauth2/accessToken Content-Typeapplication/json请求体参数参数类型必填说明clientIdString是应用的 Client ID即原 AppKeyclientSecretString是应用的 Client Secret即原 AppSecret2. 使用 curl 调用curl--requestPOSThttps://api.dingtalk.com/v1.0/oauth2/accessToken\--headerContent-Type: application/json\--data-raw{ clientId: 你的ClientId, clientSecret: 你的ClientSecret }成功响应示例{accessToken:eyJ0eXAiOiJKV1QiLCJhbGciOi...,expireIn:7200}返回参数说明accessToken调用服务端接口的身份凭证expireIn有效期单位为秒3. Token 缓存原则不要在每次业务请求时重新获取 Token。正确做法是将 Token 缓存到 Redis 或应用内存缓存时间应略小于接口返回的expireIn多实例部署时使用共享缓存Token 失效后重新获取并控制并发刷新不要把 Token 记录到普通业务日志。五、调用服务端接口新版接口通常将 Token 放在请求头中x-acs-dingtalk-access-token: ACCESS_TOKEN正式编码前建议先阅读接口详情页重点确认请求地址、HTTP Method、支持的应用类型、权限要求和参数位置。下面以根据用户 ID 查询用户详情为例说明调用方式。1. 请求信息请求方式GET 请求地址https://api.dingtalk.com/v1.0/contact/users/{userId}常用参数参数位置类型必填说明userIdPathString是钉钉用户的 userIdlanguageQueryString否通讯录语言如 zh_CN 或 en_USx-acs-dingtalk-access-tokenHeaderString是上一步取得的 Token2. 使用 curl 调用curl--requestGET\https://api.dingtalk.com/v1.0/contact/users/用户ID?languagezh_CN\--headerx-acs-dingtalk-access-token: ACCESS_TOKEN成功响应通常包含用户姓名、手机号、部门 ID、职位和工作状态等字段。实际返回字段受接口权限和通讯录授权范围影响。3. 通用请求结构不同接口的参数位置不能混用Path 参数拼接在 URL 路径中例如 /users/{userId} Query 参数拼接在 ? 后例如 ?languagezh_CN Header 参数身份凭证、内容类型等 Body 参数POST/PUT 请求提交的 JSON 数据调用任何接口前建议依次检查请求方法、URL、权限点、Token 类型、参数位置、字段类型和应用可见范围。下面是使用 Postman 调用旧版部门列表接口的示例。截图中的 Token、部门 ID、部门名称及扩展数据均已打码下面是按部门分页查询用户列表的示例。截图中的 Token、部门 ID、手机号、姓名、UnionId 和 UserId 等数据均已打码上述 Postman 截图使用的是oapi.dingtalk.com/topapi/v2旧版接口仅用于展示参数和响应结构。新项目应优先使用目标接口文档当前推荐的版本不要混用新旧接口的 Token 传递方式。六、使用 Java 调用钉钉接口下面使用 Spring Boot 自带的RestClient演示。RestClient适用于 Spring Framework 6.1 及以上版本旧项目也可以使用RestTemplate或 OkHttp接口调用逻辑相同。1. 配置应用参数# application.ymldingtalk:client-id:${DINGTALK_CLIENT_ID}client-secret:${DINGTALK_CLIENT_SECRET}启动服务前设置环境变量exportDINGTALK_CLIENT_ID你的ClientIdexportDINGTALK_CLIENT_SECRET你的ClientSecretWindows PowerShell$env:DINGTALK_CLIENT_ID你的ClientId$env:DINGTALK_CLIENT_SECRET你的ClientSecret2. 定义配置类importorg.springframework.boot.context.properties.ConfigurationProperties;ConfigurationProperties(prefixdingtalk)publicrecordDingTalkProperties(StringclientId,StringclientSecret){}在启动类启用配置绑定importorg.springframework.boot.context.properties.EnableConfigurationProperties;EnableConfigurationProperties(DingTalkProperties.class)SpringBootApplicationpublicclassApplication{publicstaticvoidmain(String[]args){SpringApplication.run(Application.class,args);}}3. 获取并缓存 Tokenimportjava.time.Instant;importjava.util.Map;importorg.springframework.stereotype.Service;importorg.springframework.web.client.RestClient;ServicepublicclassDingTalkTokenService{privatefinalRestClientrestClientRestClient.create(https://api.dingtalk.com);privatefinalDingTalkPropertiesproperties;privatevolatileStringaccessToken;privatevolatilelongexpiresAt;publicDingTalkTokenService(DingTalkPropertiesproperties){this.propertiesproperties;}publicStringgetAccessToken(){longnowInstant.now().getEpochSecond();if(accessToken!nullnowexpiresAt){returnaccessToken;}synchronized(this){nowInstant.now().getEpochSecond();if(accessToken!nullnowexpiresAt){returnaccessToken;}TokenResponseresponserestClient.post().uri(/v1.0/oauth2/accessToken).body(Map.of(clientId,properties.clientId(),clientSecret,properties.clientSecret())).retrieve().body(TokenResponse.class);if(responsenull||response.accessToken()null){thrownewIllegalStateException(获取钉钉 accessToken 失败);}accessTokenresponse.accessToken();// 提前 5 分钟刷新避免临界时间请求失败expiresAtnowMath.max(response.expireIn()-300,60);returnaccessToken;}}publicrecordTokenResponse(StringaccessToken,longexpireIn){}}上述内存缓存适合单实例演示。生产环境多实例部署时应改用 Redis并通过分布式锁避免多个实例同时刷新 Token。4. 查询用户详情importjava.util.Map;importorg.springframework.stereotype.Service;importorg.springframework.web.client.RestClient;ServicepublicclassDingTalkContactService{privatefinalRestClientrestClientRestClient.create(Cdingtalk.com);privatefinalDingTalkTokenServicetokenService;publicDingTalkContactService(DingTalkTokenServicetokenService){this.tokenServicetokenService;}publicMap?,?getUser(StringuserId){returnrestClient.get().uri(uriBuilder-uriBuilder.path(/v1.0/contact/users/{userId}).queryParam(language,zh_CN).build(userId)).header(x-acs-dingtalk-access-token,tokenService.getAccessToken()).retrieve().body(Map.class);}}实际项目中建议为每个接口定义明确的请求和响应 DTO不要长期使用Map这样可以在编译期发现字段类型错误。七、使用 API 调试工具钉钉开放平台的接口文档通常提供API 调试功能。首次接入时可以先在调试工具中完成调用再编写业务代码。推荐调试顺序在接口文档中确认应用类型和所需权限选择组织和应用填写请求参数并发起调用保存成功请求的 URL、Header、Body 和响应在 Postman 或 curl 中复现最后封装到项目代码中。切勿将调试工具生成的真实 Token、手机号或用户信息复制到博客、工单和公共代码仓库中。八、接收钉钉事件如果系统需要实时感知员工变更、审批状态或机器人消息可以配置事件订阅。事件订阅分为 HTTP 回调和 Stream 模式具体可用方式以应用后台为准。1. HTTP 回调模式基本流程如下钉钉产生事件 → 请求回调地址 → 服务端验证签名并解密 → 处理业务 → 按要求响应配置时通常需要公网可访问的 HTTPS 回调 URL回调 Token数据加密密钥 AES Key订阅的事件类型。服务端应注意严格按照文档进行签名校验和数据解密先快速响应再异步处理耗时业务使用事件 ID 或业务 ID 做幂等防止重复消费记录请求 ID 和处理结果但不要记录完整敏感数据正确处理钉钉的回调地址校验请求。本地开发时localhost无法被钉钉直接访问需要使用具有 HTTPS 地址的测试环境或内网穿透工具。2. Stream 模式Stream 模式由本地应用主动向钉钉建立长连接。钉钉不需要访问开发机因此即使服务只有192.168.x.x、10.x.x.x等内网 IP也无需公网域名、固定公网 IP 或内网穿透。内网 Java 服务 ──主动建立 WSS 长连接── 钉钉 Stream 服务 内网 Java 服务 ──────事件推送───────── 钉钉 Stream 服务开发机仍需能够访问互联网并允许出站 HTTPS/WSS 连接。如果公司代理或防火墙拦截 WebSocket需要先开放相关出站访问。2.1 在钉钉后台启用 Stream 模式进入应用的事件订阅配置开发者后台 → 应用开发 → 企业内部应用 → 目标应用 → 事件与回调选择Stream 模式然后勾选需要订阅的事件类型并保存。事件 Topic 在开发者后台选择不需要在 Java 代码中逐个填写。应用使用前文记录的Client ID和Client Secret建立连接不需要配置 HTTP 回调 URL、回调 Token 和 AES Key。2.2 添加 Java SDK在pom.xml中添加钉钉 Stream SDKdependencygroupIdcom.dingtalk.open/groupIdartifactIddingtalk-stream/artifactIdversion1.3.12/version/dependency版本会持续更新接入时可在 Maven Central 或官方 SDK 仓库确认最新稳定版本。2.3 配置应用凭证复用前文的环境变量避免把密钥直接写入配置文件dingtalk:client-id:${DINGTALK_CLIENT_ID}client-secret:${DINGTALK_CLIENT_SECRET}2.4 编写事件处理器importcom.dingtalk.open.app.api.GenericEventListener;importcom.dingtalk.open.app.api.message.GenericOpenDingTalkEvent;importcom.dingtalk.open.app.stream.protocol.event.EventAckStatus;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;publicclassDingTalkEventConsumerimplementsGenericEventListener{privatestaticfinalLoggerlogLoggerFactory.getLogger(DingTalkEventConsumer.class);OverridepublicEventAckStatusonEvent(GenericOpenDingTalkEventevent){log.info(收到钉钉事件type{}, eventId{}, corpId{},event.getEventType(),event.getEventId(),event.getEventCorpId());// 根据 eventType 分发业务生产环境建议先写入消息队列再返回成功handleEvent(event.getEventType(),event.getEventId(),event.getData());returnEventAckStatus.SUCCESS;}privatevoidhandleEvent(StringeventType,StringeventId,Objectdata){// 使用 eventId 做幂等避免重复处理// TODO 在这里处理通讯录、审批等事件}}2.5 建立 Stream 长连接importcom.dingtalk.open.app.api.OpenDingTalkClient;importcom.dingtalk.open.app.api.OpenDingTalkStreamClientBuilder;importcom.dingtalk.open.app.api.security.AuthClientCredential;importjakarta.annotation.PostConstruct;importorg.springframework.stereotype.Component;ComponentpublicclassDingTalkStreamListener{privatefinalDingTalkPropertiesproperties;privateOpenDingTalkClientclient;publicDingTalkStreamListener(DingTalkPropertiesproperties){this.propertiesproperties;}PostConstructpublicvoidstart()throwsException{clientOpenDingTalkStreamClientBuilder.custom().credential(newAuthClientCredential(properties.clientId(),properties.clientSecret())).registerAllEventListener(newDingTalkEventConsumer()).build();client.start();}}如果项目使用 Spring Boot 2应将jakarta.annotation.PostConstruct改为javax.annotation.PostConstruct。启动应用后日志中出现以下内容说明连接成功[DingTalk] connection is established, connectionId...此时在钉钉中触发已订阅事件即可在本地服务收到推送。2.6 内网开发注意事项Stream 模式解决的是钉钉无法主动访问内网 IP的问题开发机必须能正常访问钉钉公网服务同一个应用启动多个实例时事件可能分发到任意连接不适合多人共用应用凭证调试处理事件时使用eventId做幂等避免重复写入回调线程中不要执行长耗时任务可先投递消息队列监听进程退出后无法接收事件生产环境应配置进程守护和连接状态告警不要输出事件完整数据通讯录、审批内容可能包含敏感信息。九、旧版与新版接口的区别开发时可能同时看到两种接口风格旧版接口https://oapi.dingtalk.com/... 新版接口https://api.dingtalk.com/v1.0/...两者在 Token 传递位置、请求参数和响应结构上可能不同新版接口通常通过x-acs-dingtalk-access-token请求头传递 Token部分旧版接口通过 URL 查询参数传递access_token不要根据接口名称自行拼接地址不要把旧版接口的请求示例直接套用到新版接口新项目优先采用官方当前推荐的接口和 SDK。十、常见错误及排查方法现象常见原因处理方法获取 Token 失败Client ID 或 Client Secret 错误从应用凭证页面重新复制检查环境变量无接口调用权限未申请权限或管理员未授权对照接口文档检查权限点查询不到用户用户不在通讯录授权或应用可见范围扩大合理范围确认 userId 所属组织IP 不在白名单实际公网出口 IP 与配置不一致在部署服务器确认出口 IPToken 无效或过期缓存时间错误、多个实例覆盖提前刷新并使用共享缓存参数错误Path、Query、Header、Body 放置错误对照文档逐项核对参数位置和类型回调收不到地址不可公网访问、证书或订阅配置错误检查 HTTPS、网络、事件类型和发布状态回调重复处理钉钉重试或程序重复消费使用事件 ID/业务 ID 实现幂等排查时应优先保存以下信息接口名称、请求时间、HTTP 状态码、钉钉错误码、错误信息、requestId不要在日志或截图中暴露Client Secret和完整accessToken。十一、安全与上线检查正式上线前建议逐项确认Client Secret 已通过环境变量或密钥管理服务注入仓库历史中不存在应用密钥和 Token应用只申请了必要权限通讯录范围和应用可见范围符合业务要求出口 IP 固定且白名单配置正确Token 已缓存并具备刷新和失败重试机制请求设置了合理的连接与读取超时重试只用于适合重试的请求并设置退避策略回调完成签名校验、解密、幂等和异常监控日志对手机号、身份证号等个人信息进行了脱敏测试应用与生产应用使用不同的凭证和配置。十二、总结钉钉接口开发的核心流程可以概括为创建应用 → 配置可见范围和安全设置 → 申请接口权限 → 获取并缓存 accessToken → 按文档调用 OpenAPI → 配置事件订阅 → 完成监控与安全检查完成本文步骤后就具备了接入通讯录、审批、考勤、待办和机器人等业务能力的基础。后续开发某个具体功能时应先阅读对应接口的最新文档特别关注权限点、参数位置、调用频率和应用类型限制。
返回列表