![42ec2b8eb09254080a1815e88a3ea141.png](https://i-blog.csdnimg.cn/blog_migrate/66f212aadc32581cd347ed756367be24.jpeg)
最近公司要开发企业微信端的 Worktile,以前做的是企业微信内部应用,所以只适用于私有部署客户,而对于公有云客户就无法使用,所有就准备开发企业微信的第三方应用,本文主要介绍在调研阶段遇到的山珍海味。
开发之前你需要前注册为第三方服务商,然后用第三方服务商的账号创建应用,创建之后只需要管理员授权应用,第三方服务商即可为用户提供服务。
一、注册第三发服务商
登陆服务商官网,注册成为服务商,并登陆服务商管理后台。
二、配置开发信息
在创建应用之前,首先要配置好通用开发参数
![a10a371cc71a332d3a6887f45bda186b.png](https://i-blog.csdnimg.cn/blog_migrate/5ed740a9ab2407469805b16183307e08.jpeg)
在填写系统事件接收 url 时,要正确响应企业微信验证 url 的请求。这个可以参考企业微信后台,自建应用的接收消息的 api 设置。
在企业的管理端后台,进入需要设置接收消息的目标应用,点击“接收消息”的“设置API接收”按钮,进入配置页面。
![89a65ce86a171351fcefb53b5a4607a2.png](https://i-blog.csdnimg.cn/blog_migrate/105a977102ee499199eacd0294efa931.jpeg)
要求填写应用的 URL、Token、EncodingAESKey 三个参数
- URL 是企业后台接收企业微信推送请求的访问协议和地址,支持 http 或 https 协议(为了提高安全性,建议使用 https)。
- Token 可由企业任意填写,用于生成签名。
- EncodingAESKey 用于消息体的加密,是 AES 密钥的 Base64 编码。
2.1 验证 url 有效性
当点击保存的时候,企业微信会发生一条 get 请求到填写的 url
比如 url 设置的是https://api.worktile.com, 企业微信将发送如下验证请求:
请求地址:https://api.worktile.com/?msg_signature=ASDFQWEXZCVAQFASDFASDFSS×tamp=13500001234&nonce=123412323&echostr=ENCRYPT_STR
![1afc856a63fb1cb24473bd6433bcb466.png](https://i-blog.csdnimg.cn/blog_migrate/b6104755466925c035419c532a972812.jpeg)
2.1.1 通过参数 msg_signature 对请求进行校验
首先要把刚才配置时随机生成的 token, timestamp, nonce, msg_encrypt 进行 sha1 加密,这里我们可以直接使用 npm 模块 sha1 进行加密,然后判断得到的 str 是否和 msg_signature 相等。
function sha1(str) { const md5sum = crypto.createHash('sha1'); md5sum.update(str); const ciphertext = md5sum.digest('hex'); return ciphertext;}function checkSignature(req, res, encrypt) { const query = req.query; console.log('Request URL: ', req.url); const signature = query.msg_signature; const timestamp = query.timestamp; const nonce = query.nonce; let echostr; console.log('encrypt', encrypt); if (!encrypt) { echostr = query.echostr; } else { echostr = encrypt; } console.log('timestamp: ', timestamp); console.log('nonce: ', nonce); console.log('signature: ', signature); // 将 token/timestamp/nonce 三个参数进行字典序排序 const tmpArr = [token, timestamp, nonce, echostr]; const tmpStr = sha1(tmpArr.sort().join('')); console.log('Sha1 String: ', tmpStr); // 验证排序并加密后的字符串与 signature 是否相等 if (tmpStr === signature) { // 原样返回echostr参数内容 const result = _decode(echostr); console.log('last', result); console.log('Check Success'); return result; } else { console.log('Check Failed'); return 'failed'; }}
2.1.2 解密 echostr 得到 msg 并返回
密文解密过程:
- 对刚才生成的 AESKey 进行 base64 解码
const EncodingAESKey = '21IpFqj8qolJbaqPqe1rVTAK5sgkaQ3GQmUKiUQLwRe';let aesKey = Buffer.from(EncodingAESKey + '=', 'base64');
- 对 AESKey 进行 aes-256-cbc 解密
function _decode(data) { let aesKey = Buffer.from('21IpFqj8qolJbaqPqe1rVTAK5sgkaQ3GQmUKiUQLwRe' + '=', 'base64'); let aesCipher = crypto.createDecipheriv("aes-256-cbc