这篇文章主要介绍NodeJS开发钉钉回调接口实现AES-CBC加解密,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
钉钉小程序后台接收钉钉开放平台的回调比较重要,比如通讯录变动的回调,审批流程的回调都是在业务上十分需要的。回调接口时打通钉钉平台和内部系统的重要渠道。
但是给回调的接口增加了一些障碍,它需要支持回调的服务器的接口支持AES-CBC加解密。不然无法成功注册或解析内容。
钉钉官方文档中给出了JAVA,PHP,C#的后台SDK和demo,但是却没有Node服务器的代码支持,这让占有率很高的node服务器非常尴尬,难道node就不能作为钉钉平台的回调服务器么
好在钉钉已经开放了其加密算法,可以通过加密流程自己写一套JavaScript版的加解密程序,然后将node服务器注册为钉钉的回调接口。
首先,看一下钉钉回调接口的注册流程
首先,是由开发者主动发起一个POST请求到钉钉开放平台,传过去回调的URL,然后钉钉在这个请求中返回一个ok,如下图
在这里,我申请了通讯录加人或修改人事件的回调。
在这个接口请求完毕之后,钉钉会迅速的向你请求参数中写的url发送一个POST请求,如下
{"encrypt":"ihVRgn3eZZrCYHfAW4Lbh9eoOcpy1VddxGS9IIYsteFgAxpPN9ZaKKp4EH/7ArtmVEACxmyGCdUFtGuXxfNfcbXXXXXXXXXXXXXXXXXXXkGy+Oq/hIN"}
此时,钉钉要求我们“success”加密,然后在服务器中响应。
AES是一种对称性加密,即加密者通过一个密钥进行加密,将密文发送给接收人,接收人通过相同的密钥进行解密。但是CBC这种模式下,还需要一个偏移,或者说IV向量进行加解密。所以在加解密的时候实际上需要两个参数,密钥和IV。换句话说,钉钉回调接口使用的加密方式为AES-256-CBC模式
按照文档要求,我们返回的JSON中需要包含4个字段
其中,nonce是可以随便写的字符串,长度也没有限制,是用来增加msg_signature的变化度的。
timeStamp是10位数的时间戳,JavaScript默认时间戳是13位的,我们需要除以1000或者截取后3位。
encrypt是一段base64编码后的字符串,被编码的是“sucess”被加密后的密文
msg_signature是一段hash值,是将其余3个字符串,加上我们注册接口时设定的自定义token,4个字符串排序好,通过SHA1算法HASH后的值,用来验证完整性的。具体如下
最难以解决的就是encrypt字段了,还好在JS界谷歌已经给我们准备好了CryptoJS库,不用几行代码就可以解决问题。
首先观察下这个encrypt字段的形成逻辑:
需要被加密的明文由四个部分组成,分别是
16个字节的随机字符串:ASCII编码中,一个字符就占1个字节(8位),所以这里我们随便填16个字母组成的字符串就行
4个字节的msg长度:这里的长度不是文本格式的长度,而是4*8=32位二进制表示的长度,文档中没有明确指出是填msg的字节长度,还是比特位数,通过我个人验证,此处应该填msg的字节数。由于"success"由7个ASCII字符组成,所以长度为7,以4个字节的二进制表示就是
00000000 00000000 00000000 00000111
在JS中,要想把二进制数转化成字节,可以先换成十进制,然后使用String.fromCharCode(0)方法,转换为字节。所以此处要想用字符串表示,就是把0,0,0,7当作ASCII码转换为不可见字符
var lengthString=String.fromCharCode (0) + String.fromCharCode (0) + String.fromCharCode (0) + String.fromCharCode (7)
明文味精:就是字符串“success"
美元关键:我是企业内部开发,Corpid可以在钉钉开发者后台看到
有了明文,下一步就是进行加密