Python调用钉钉机器人发送Markdown消息签名失败怎么解决?

文章导读
Python 调用钉钉机器人签名失败通常是因为时间戳格式错误、签名计算字符串缺少换行符或 URL 编码处理不当。最推荐的处理方向是严格按照钉钉开放平台的 HMAC-SHA256 算法规范,确认时间戳为毫秒级,并对签名结果进行 URL Encode。
📋 目录
  1. 快速处理思路
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 常见问题
  7. 参考来源
A A

Python 调用钉钉机器人签名失败通常是因为时间戳格式错误、签名计算字符串缺少换行符或 URL 编码处理不当。最推荐的处理方向是严格按照钉钉开放平台的 HMAC-SHA256 算法规范,确认时间戳为毫秒级,并对签名结果进行 URL Encode。

先说结论:签名失败核心在于加签字符串构造或编码格式不符合钉钉安全校验规则,需重点检查时间戳单位和换行符。

  • 先确认:Secret 密钥复制时是否包含多余空格,时间戳是否为 13 位毫秒数。
  • 先处理:使用标准 HMAC-SHA256 算法,字符串格式为“时间戳 + 换行符 + 密钥”。
  • 再验证:发送请求后观察钉钉机器人返回的 errcode 是否为 0。

快速处理思路

以下 Python 代码片段实现了标准的签名计算逻辑,可直接替换现有签名函数进行验证。

import hmac
import hashlib
import base64
import urllib.parse
import time

def get_sign(secret):
    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))
    return timestamp, sign

将返回的 timestamp 和 sign 拼接到 webhook URL 中,格式为webhook×tamp={timestamp}&sign={sign}

为什么会这样

签名失败本质是客户端生成的签名字符串与钉钉服务器端计算结果不一致。钉钉自定义机器人安全设置中,签名机制要求使用 HMAC-SHA256 算法,对特定格式的字符串进行加密并 Base64 编码。如果时间戳单位错误(如使用秒而非毫秒)、字符串中间缺少换行符\n、或最终签名未进行 URL 编码,都会导致校验不通过。

分步处理

步骤 1:检查 Secret 密钥

登录钉钉机器人管理后台,重新复制 Secret 密钥。适用场景:初次配置或更换机器人时。操作动作:确保密钥前后无空格,字符完整。验证结果:打印密钥长度,通常为一串固定长度的字符。风险边界:密钥泄露会导致安全风险,不要提交到代码仓库。

步骤 2:校验时间戳格式

确认代码中获取的时间戳是毫秒级。适用场景:所有签名请求。操作动作:使用time.time() * 1000并取整。验证结果:打印时间戳,确认是 13 位数字。风险边界:时间戳过期会导致签名失效,建议每次请求动态生成。

步骤 3:核对签名字符串构造

Python调用钉钉机器人发送Markdown消息签名失败怎么解决?

确认拼接字符串中包含换行符。适用场景:签名计算逻辑编写。操作动作:使用timestamp + '\n' + secret格式。验证结果:打印string_to_sign确认中间有换行。风险边界:换行符必须是\n,不能是\r\n或空格。

步骤 4:检查 URL 编码

对生成的 Base64 签名进行 URL 编码。适用场景:构建最终请求 URL。操作动作:使用urllib.parse.quote_plus。验证结果:确认 URL 中sign参数无非法字符。风险边界:部分语言库默认不编码,需手动处理。

怎么验证是否生效

发送一条测试消息后,检查 Python 程序接收到的 HTTP 响应内容。如果签名为效,钉钉接口返回的 JSON 中errcode字段应为0errmsgok。如果签名失败,errcode通常为313004(签名验证失败)或类似安全校验错误码。同时在钉钉群内观察是否收到消息,未收到且接口报错即表示验证未通过。

常见坑

1. 时间戳过期:签名有效时间通常为请求时刻前后有限范围内,不要使用固定时间戳。
2. 编码不一致:确保所有字符串操作均使用 UTF-8 编码,避免中文环境下的默认编码差异。
3. 换行符错误:Windows 系统下注意不要误用\r\n,必须严格使用\n
4. 密钥混淆:多个机器人对应多个 Secret,确认代码中使用的 Secret 与当前 webhook 匹配。

常见问题

时间戳必须是多少位?

必须是 13 位毫秒级时间戳。使用秒级时间戳会导致签名计算结果错误,钉钉服务器校验不通过。

Secret 密钥在哪里获取?

在钉钉群机器人设置页面的“安全设置”栏目中,开启“签名”后会显示 Secret,需手动复制保存。

签名和 IP 白名单需要同时配置吗?

不需要同时生效,但可以同时开启。签名机制用于验证请求合法性,IP 白名单用于限制来源网络,建议至少开启签名。

参考来源

1. 钉钉开放平台 - 自定义机器人接入
URL: https://open.dingtalk.com/document/robots/custom-robot-access