回调通知说明
回调说明
回调通知都是 POST 请求,JSON格式("Content-Type":"application/json"):
(如果得到的是GET请求,请确认回调地址是否存在http到https的转发)
回调通知内容可以自定义是否,可以使用签名机制对内容进行验证;
回调通知 Url 要求:POST 请求能够正常返回 200;
如果配置了回调 Url地址,但是没有收到回调通知,请确认下回调地址提供是否正确,建议日志记录一下接收到的请求,方便排查问题!
支持的回调场景
通知类型以 MsgType 做区分,按照回调通知类型主要分为:
- 企业与员工认证与授权回调
- 印章相关回调
- 模板相关回调
- 合同发起与签署相关回调
- 文件资源相关回调
- 其他功能回调
回调加密与通知校验
回调消息加解密
新建应用号时,如果配置了“回调加密CallbackKey(可选参数)”,
电子签的回调请求体会进行加密处理,需要客户使用配置的CallbackKey进行解密得到结构体。
注意:配置了CallbackKey即会开启消息加密,去掉即为关闭。建议固定了之后不要变动。
解密步骤为
- 对收到的数据进行 Base64 解码得到密文。
- 对密文进行对称解密,算法为 AES-256-CBC,密钥为腾讯电子签提供的 CallbackUrlKey,IV 取 CallbackUrlKey 值的前16位,数据采用 PKCS#7 填充。
- 解密得到的数据为输入参数的 Json 格式。
解密代码可以参考 解密代码Demo
回调通知校验
新建应用号时,如果配置了“回调签名验证TOKEN(可选参数)”,
电子签的回调请求会在header中附带签名参数[Content-Signature],客户方用来验证请求来源确实电子签,保证安全性。
原理可参考:https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks
当接收到回调时:
取出header [Content-Signature]
验证签名
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
- 如果验证通过,继续处理。如果不通过,忽略该请求
回调通用结构体
未加密/解密后的结构体(Json)
参数名称 | 参数类型 | 参数描述 |
---|---|---|
MsgId | string | 消息唯一Id |
MsgType | string | 消息类型 |
MsgVersion | string | 消息版本,第三方应用集成固定为 ThirdPartyApp |
MsgData | json | 消息数据 |
加密的结构体(Json)
参数名称 | 参数类型 | 参数描述 |
---|---|---|
encrypt | string | 加密后的消息体(通过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 时
回调样例
- 回调请求包(加密):
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
}
}
- 回调请求包(不加密):
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}}