搭建回调服务
回调服务介绍
进行应用接入时,需要开发者先搭建好回调服务,用于接收平台的回调请求。
1. 什么时候需要回调服务
回调服务可以及时获取到状态变化。比如:机构授权了应用,平台侧会同步给开发者;通讯录发生变化时,不需要定时去拉取通讯录对比,而是实时地获取到变化的通讯录结点,进行同步。
2. 如何配置回调服务
配置回调服务,需要有三个配置项,分别是:URL, Token, EncodingAESKey。其中 URL 由开发者在应用接入平台配置,Token 和 EncodingAESKey 在平台自动随机生成。
首先,URL 为回调服务地址,由开发者搭建,用于接收通知消息或者事件。其次,Token 用于计算签名,由英文或数字组成且长度不超过32位的自定义字符串。开发者提供的URL是公开可访问的,这就意味着拿到这个URL,就可以往该链接推送消息。
那么 URL 服务需要解决两个问题:
- 如何分辨出是否为教育号来源
- 如何分辨出推送消息的内容是否被篡改
通过数字签名就可以解决上述的问题。具体为:约定Token作为密钥,仅开发者和平台知道,在传输中不可见,用于参与签名计算。教育号在推送消息时,将消息内容与Token计算出签名。开发者接收到推送消息时,也按相同算法计算出签名。如果为同一签名,则可信任来源为教育号,并且内容是完整的。如果非教育号来源,由于攻击者没有正确的Token,无法算出正确的签名。如果消息内容被篡改,由于开发者会将接收的消息内容与Token重算一次签名,该值与参数的签名不一致,则会拒绝该请求。
最后,EncodingAESKey 用于消息内容加密,由英文或数字组成且长度为43位的自定义字符串。由于消息是在公开的因特网上传输,消息内容是可被截获的,如果内容未加密,则截获者可以直接阅读消息内容。若消息内容包含一些敏感信息,就非常危险了。EncodingAESKey就是在这个背景基础上提出,将发送的内容进行加密,并组装成一定格式后再发送。
回调服务需要实现哪些功能
配置回调服务时,要求能够接收 HttpPost 请求。
应用完成市场上架后,教育号会往 URL 服务上定时发送 Post 请求推送 suite_ticket,并带上签名及密文参数到 URL 服务上,如果 URL 服务检查签名通过,并能正确返回明文字符串 "success",则回调验证通过。
后续的业务请求(比如应用授权等),都会类似的方式(签名+密文)向服务URL推送消息。URL服务验证签名通过后,需要将POST数据解密,就可以得到对应的业务消息明文。
支持 Http Post 请求接收业务数据
假设接收消息的URL设置为 http://notifyurl.com
请求方式:POST
请求地址 :http://notifyurl.com/?msg_signature=ASDFQWEXZCVAQFASDFASDFSS×tamp=13500001234&nonce=123412323
请求体(xml 格式):
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<Encrypt><![CDATA[msg_encrypt]]></Encrypt>
</xml>
参数说明:
参数 | 类型 | 说明 |
---|---|---|
msg_signature | String | 教育号加密签名,msg_signature 结合了开发者填写的 token、请求中的 timestamp、nonce 参数、加密的消息体 |
timestamp | Integer | 时间戳。与 nonce 结合使用,用于防止请求重放攻击。 |
nonce | String | 随机数。与 timestamp 结合使用,用于防止请求重放攻击。 |
ToUserName | String | 第三方应用回调该值为 SuiteId |
Encrypt | String | 消息结构体加密后的字符串 |
开发者收到消息后,需要作如下处理:
其中步骤1~2可以直接使用 解密函数 一步到位。
消息解密方案说明
签名校验与解密方法和企业微信的一致,开发者可直接参考 加解密库下载与返回码
消息体签名校验
为了让开发者确认调用来自教育号,教育号在回调给接收消息url时会带上消息签名,以参数msg_signature标识,机构需要验证此参数的正确性后再解密。 验证步骤如下:
- 计算签名
dev_msg_signature=sha1(sort(token、timestamp、nonce、msg_encrypt))。
sort的含义是将参数值按照字母字典排序,然后从小到大拼接成一个字符串 sha1处理结果要编码为可见字符,编码的方式是把每字节散列值打印为%02x(即16进制,C printf语法)格式,全部小写
- 比较dev_msg_signature和msg_signature是否相等,相等则表示验证通过
- 被动响应消息时,开发者同样需要用如上方法生成签名并传给教育号
密文解密得到msg的过程
- 对密文BASE64解码
aes_msg=Base64_Decode(msg_encrypt)
- 使用AESKey做AES-256-CBC解密
rand_msg=AES_Decrypt(aes_msg)
- 去掉rand_msg头部的16个随机字节和4个字节的msg_len,截取msg_len长度的部分即为msg,剩下的为尾部的receiveid
- 验证解密后的receiveid、msg_len