钉钉小程序PHP后端验证code需调用https://oapi.dingtalk.com/sns/getuserinfo_bycode接口,以POST方式发送含tmp_auth_code的JSON体,并在URL中保留无效access_token占位;返回user_info中的userid(企业内唯一)或openid(跨企业通用),须结合corpId存储以确保多企业场景下用户标识准确。

钉钉小程序 PHP 后端怎么验证 code 换取用户信息
钉钉小程序调用 dd.getAuthCode 获取的 code,不能直接拿去微信那套逻辑用——它必须发给钉钉服务端接口 https://oapi.dingtalk.com/sns/getuserinfo_bycode,且需携带 appkey 和 appsecret 换取 userid 和 openid。
常见错误是:把 code 当成 JWT 或本地解码,或者漏传 appsecret 导致返回 {"errcode":40001,"errmsg":"invalid credential"}。
- 必须用 POST 请求,
Content-Type: application/json - 请求体是 JSON:
{"tmp_auth_code": "xxx"},不是 query 参数 -
appkey和appsecret来自钉钉开放平台「小程序」配置页,不是企业内部应用的凭证 - 接口返回的
userid是企业内唯一 ID,openid才是跨企业通用标识(如需多企业支持)
PHP cURL 调用钉钉 sns/getuserinfo_bycode 的关键写法
别用 file_get_contents 拼 URL,钉钉这个接口只认 POST + JSON,且对 SSL、超时、错误响应码敏感。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 用
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false)临时绕过证书问题(仅开发),生产必须配好 CA 包 - 显式设置
CURLOPT_TIMEOUT为 10 秒以内,钉钉接口偶有延迟,别让 PHP 卡住 - 检查
curl_getinfo($ch, CURLINFO_HTTP_CODE)是否为 200,非 200 时curl_error($ch)往往比响应体更有用 - 响应体要
json_decode($res, true),注意钉钉返回字段名是user_info(不是data或result)
示例片段:
$ch = curl_init('https://oapi.dingtalk.com/sns/getuserinfo_bycode?access_token='.$access_token);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['tmp_auth_code' => $code]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
$res = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) { /* 处理网络或钉钉服务异常 */ }
$data = json_decode($res, true);
if (isset($data['user_info']['userid'])) { /* 成功 */ }
为什么 access_token 不是调用 getuserinfo_bycode 所需的参数
这是最常被文档误导的一点:钉钉官方文档里 getuserinfo_bycode 接口 URL 写着 ?access_token=xxx,但实际测试发现——传不传、传错、甚至传企业 access_token 都不影响返回用户信息。真正起作用的是请求体里的 tmp_auth_code 和 Header 中的 appkey/appsecret 认证。
原因在于:该接口本质是「免登授权交换」,钉钉用 tmp_auth_code 反查会话上下文,access_token 在这里只是冗余占位。但如果你删掉 URL 里的 access_token,接口会直接返回 400 错误。
- 必须保留 URL 中的
access_token参数(哪怕填个假值),否则钉钉网关拒收 - 这个
access_token不需要有效,也不需要定期刷新——它只是路由标识,不是认证凭据 - 真正的认证靠的是请求头中由
appkey和appsecret算出的签名(SDK 会自动处理)
PHP 获取到 userid 后,怎么安全地关联到自己数据库用户
拿到 userid 不代表能直接当用户 ID 存库——它只在当前企业内唯一,换家企业就变;而用户可能在多个钉钉组织里用同一个手机号注册,但 userid 完全不同。
所以不能只存 userid,得结合上下文判断:
- 如果小程序只服务于单个钉钉企业,用
userid+corpId作为联合主键最稳妥 - 如果需支持多企业,优先用
openid(但注意:只有开通了「免登授权」并勾选「获取用户基本信息」才返回) - 千万别用
mobile字段做关联——它默认不返回,开启需额外申请权限,且用户可隐藏 - 首次登录建议走「静默授权」流程,避免弹窗;若需手机号等敏感信息,必须显式调用
dd.requestAuthCode并在后台再换一次
复杂点在于:钉钉不提供「根据 userid 查企业」的反向接口,所以你数据库里每条用户记录最好存一份 corpId,否则跨企业场景下无法区分同名 userid。



















