跳到主要内容

回调通知说明

回调说明

回调通知都是 POST 请求,JSON格式("Content-Type":"application/json"):

(如果得到的是GET请求,请确认回调地址是否存在http到https的转发)

回调通知内容可以自定义是否,可以使用签名机制对内容进行验证;

回调通知 Url 要求:POST 请求能够正常返回 200;

如果配置了回调 Url地址,但是没有收到回调通知,请确认下回调地址提供是否正确,建议日志记录一下接收到的请求,方便排查问题!

支持的回调场景

通知类型以 MsgType 做区分,按照回调通知类型主要分为:

  • 企业与员工认证与授权回调
  • 印章相关回调
  • 模板相关回调
  • 合同发起与签署相关回调
  • 文件资源相关回调
  • 其他功能回调

回调加密与通知校验

回调消息加解密

新建应用号时,如果配置了“回调加密CallbackKey(可选参数)”,

电子签的回调请求体会进行加密处理,需要客户使用配置的CallbackKey进行解密得到结构体。

注意:配置了CallbackKey即会开启消息加密,去掉即为关闭。建议固定了之后不要变动。

解密步骤为

  1. 对收到的数据进行 Base64 解码得到密文。
  2. 对密文进行对称解密,算法为 AES-256-CBC,密钥为腾讯电子签提供的 CallbackUrlKey,IV 取 CallbackUrlKey 值的前16位,数据采用 PKCS#7 填充。
  3. 解密得到的数据为输入参数的 Json 格式。

    解密代码可以参考 解密代码Demo

回调通知校验

新建应用号时,如果配置了“回调签名验证TOKEN(可选参数)”,

电子签的回调请求会在header中附带签名参数[Content-Signature],客户方用来验证请求来源确实电子签,保证安全性。

原理可参考:https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks

当接收到回调时:

  1. 取出header [Content-Signature]

  2. 验证签名

def verify_signature(payload_body)

signature = 'sha256=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), ENV['SECRET_TOKEN'], payload_body)

return halt 500, "Signatures didn't match!" unless Rack::Utils.secure_compare(signature, request.env['Content-Signature'])

end
  1. 如果验证通过,继续处理。如果不通过,忽略该请求

回调通用结构体

未加密/解密后的结构体(Json)

参数名称参数类型参数描述
MsgIdstring消息唯一Id
MsgTypestring消息类型
MsgVersionstring消息版本,第三方应用集成固定为 ThirdPartyApp
MsgDatajson消息数据

加密的结构体(Json)

参数名称参数类型参数描述
encryptstring加密后的消息体(通过CallbackKey解密后得到上面的结构体)

回调 FAQ

回调地址是否支持同时配置多个?

支持,回调地址一个应用号下只能有一个,根据您的需求不同的地址可以配置相同或者不同的 CallbackUrlKey、token。

回调地址是否支持更改或删除?

支持,您可以在控制台开发者中心中进行回调地址的配置。

回调地址配置后多长时间生效呢?

配置完成后立即生效。

为什么客户收到 FlowCallbackStatus 为4(已签署)的回调通知后,又收到了 FlowCallbackStatus 为1(待签署)的通知?

以单方签署的合同为例,FlowCallbackStatus 状态变化一般是由1变为4。少量回调可能因状态变化间隔比较短、重发、或者网络传输等原因,小几率出现到达顺序不一致,建议开发者从代码层面进行适当控制,例如状态更新为4后不能再更新为1。

电子签发送回调时超时时间是多久?

超时时间为5秒。

电子签发送回调失败后,回调最大重试次数是多少?重试机制是怎么样的呢?

回调的最大重试次数是36次;回调重试间隔随次数增加,具体如下:

1 秒、2 秒、3 秒、4 秒、5 秒、10 秒、15 秒、20 秒、25 秒、30 秒、35 秒、40 秒、45 秒、50 秒、55 秒、1 分、2 分、3 分、4 分、5 分、6 分、7 分、8 分、9 分、10 分、15 分、25 分、35 分、45 分、55 分、1 时、2 时、3 时、4 时、5 时、6 时

回调样例

  1. 回调请求包(加密):
POST /callback HTTP/1.1
Host: www.esstest.com
User-Agent: Go-http-client/1.1
Content-Length: xxx
Content-Type: application/json
Accept-Encoding: gzip

{"encrypt":"uXm2LDbslypT/mTXnKJynaj7riwJt356nGXvs/MszFshjs591sgduXpQpYXGNfox6U3Mk65Q+vCOo8CAHoMgVJVHEJl1ZmHvR1ocYNvquuVcwOK+/QN4zuH1NbkEtACLsVFgmG/B9L9pV3+i6u/uCTcFFF6LyxcgB4V7OHBwRoOUSLi/LqBTshNstW5W/mDzBPZUwed9e3Kk1Cmt7VUn+z22kyF0AoHuGuvUtVId7n+TAda7eTSty6nkFtxXk/DhvZPMeFXyN61aOa8nKSdL9bAosjjkrMYevlWhDsGeINDtSjLNmkzlEs9ZpOEMCHy8bG9vHMRuyFdW1hjBBTM/Tw=="}

此处使用 CallbackUrlKey:"TencentEssEncryptTestKey12345678" ,参考解密代码Demo解密后可获取以下明文:

!该 CallbackUrlKey 仅用于此处测试样例。

{
"MsgId": "yDwf4UUckpsjeox1URAyCMBHv7W1zDbP",
"MsgType": "OrgAuth",
"MsgVersion": "ThirdPartyApp",
"MsgData": {
"ApplicationId": "yDwftUUckpsrmwz5UEfbpqAAAAAAAAAA",
"ProxyOrganizationOpenId": "MockOpenId",
"ProxyOperatorOpenId": "MockUserOpenId",
"AuthSuccess": true
}
}
  1. 回调请求包(不加密):
POST /callback HTTP/1.1
Host: www.esstest.com
User-Agent: Go-http-client/1.1
Content-Length: xxx
Content-Type: application/json
Accept-Encoding: gzip

{"MsgId":"yDwf4UUckpsjeox1URAyCMBHv7W1zDbP","MsgType":"OrgAuth","MsgVersion":"ThirdPartyApp","MsgData":{"ApplicationId":"yDwftUUckpsrmwz5UEfbpqAAAAAAAAAA","ProxyOrganizationOpenId":"MockOpenId","ProxyOperatorOpenId":"MockUserOpenId","AuthSuccess":true}}