钉钉机器人签名错误通常由时间戳格式错误或签名字符串拼接不符合规范导致。处理重点是确保时间戳为毫秒级整数,且签名字符串使用 timestamp + '\n' + secret 格式进行 HMAC-SHA256 计算。
先说结论:签名错误核心在于加签字符串构造或编码方式不符合钉钉开放平台安全规范。
- 先确认:secret 是否完整复制,包含 SEC 前缀
- 先处理:时间戳必须为毫秒级,签名字符串需 URL 编码
- 再验证:发送请求后检查返回 JSON 中 errcode 是否为 0
快速处理思路
直接使用以下 Python 函数生成签名并发送请求,避免手动拼接字符串出错。
import hmac
import hashlib
import base64
import urllib.parse
import time
import requests
import json
def send_dingtalk_msg(webhook, secret, content):
timestamp = str(round(time.time() * 1000))
secret_enc = secret.encode('utf-8')
string_to_sign = '{}\n{}'.format(timestamp, secret)
string_to_sign_enc = string_to_sign.encode('utf-8')
hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
url = webhook + '×tamp=' + timestamp + '&sign=' + sign
headers = {'Content-Type': 'application/json'}
data = {"msgtype": "text", "text": {"content": content}}
res = requests.post(url, headers=headers, data=json.dumps(data))
return res.json()为什么会这样
钉钉机器人加签机制要求客户端使用 HMAC-SHA256 算法对特定字符串进行加密。
签名错误通常因为时间戳单位不对(用了秒而不是毫秒)、secret 缺失 SEC 前缀、或签名字符串中间缺少换行符。服务器收到请求后会用相同算法验证,不一致则拒绝。
分步处理
1. 获取密钥:在钉钉群机器人设置中查看安全设置,复制以 SEC 开头的 secret。
2. 计算时间戳:使用 Python time.time() 乘以 1000 并取整,转为字符串。
3. 构造签名字符串:格式为 时间戳 + 换行符 + secret,注意换行符是 \n 。
4. 生成签名:使用 hmac 库计算 SHA256,结果经 base64 编码后再进行 URL 编码。
5. 拼接 URL:将 timestamp 和 sign 作为参数附加到 webhook 地址后。
怎么验证是否生效
运行脚本后观察返回字典,若 errcode 为 0 且 errmsg 为 ok,表示发送成功。
同时检查钉钉群内是否收到消息,若返回签名错误码,请核对 secret 是否含有空格。
常见坑
- secret 复制时多带了空格或换行,导致哈希计算不一致。
- 时间戳用了秒级,钉钉要求毫秒级长整数。
- 签名字符串拼接时漏了中间的换行符 \n 。
- base64 编码后未做 URL 编码,特殊字符导致请求解析失败。
常见问题
时间戳必须是多少位?
必须是 13 位毫秒级时间戳,使用 10 位秒级时间戳会导致签名验证失败。
secret 在哪里获取?
在钉钉群机器人设置的安全设置栏目中,开启自定义关键词或签名后可见。
发送消息必须用 HTTPS 吗?
是的,钉钉机器人 webhook 地址强制要求 HTTPS 协议,HTTP 请求会被拒绝。
参考来源
- 钉钉开放平台 - 自定义机器人接入:https://open.dingtalk.com/document/robots/custom-robot-access