最近公司要開發企業微信端的 worktile,以前做的是企業微信內部應用,由於開發的是企業內部應用,所有隻適用於私有部署客戶,對於公有云客戶就無法使用,所有就準備開發企業微信的第三方應用,本文主要介紹在調研階段遇到的山珍海味。
開發之前你需要前註冊爲第三方服務商,然後用第三方服務商的賬號創建應用,創建之後只需要管理員授權應用,第三方服務商即可爲用戶提供服務。這裏我們主要研究第三方服務商註冊應用。
註冊第三方服務商
登陸服務商官網,註冊成爲服務商,並登陸服務商管理後臺。
配置開發信息
1、在創建應用之前,首先要配置好通用開發參數
在填寫系統事件接收 url 時,要正確響應企業微信驗證 url 的請求。這個可以參考企業微信後臺,自建應用的接收消息API。
在企業的管理端後臺,進入需要設置接收消息的目標應用,點擊“接收消息”的“設置API接收”按鈕,進入配置頁面。
要求填寫應用的 URL、Token、EncodingAESKey 三個參數,這三個參數的用處在加解密方案說明
- URL 是企業後臺接收企業微信推送請求的訪問協議和地址,支持 http 或 https 協議(爲了提高安全性,建議使用 https)。
- Token 可由企業任意填寫,用於生成簽名。
- EncodingAESKey 用於消息體的加密,是 AES 密鑰的 Base64 編碼。
驗證 URL 有效性
當點擊保存的時候,企業微信會發生一條 get 請求到填寫的 url
比如 url 設置的是https://api.worktile.com
, 企業微信將發送如下驗證請求:
參數 | 說明 |
---|---|
msg_signature | 企業微信加密簽名,msg_signature 結合了企業填寫的 token、請求中的 timestamp、nonce 參數、加密的消息體 |
timestamp | 時間戳 |
nonce | 隨機數 |
echostr | 加密的字符串。需要解密得到消息內容明文,解密後有random、msg_len、msg、receiveid 四個字段,其中 msg 即爲消息內容明文 |
企業後臺收到請求後,需要做如下操作:
- 對收到的請求做Urldecode處理
- 通過參數msg_signature對請求進行校驗,確認調用者的合法性。
- 解密echostr參數得到消息內容(即msg字段)
- 在1秒內響應GET請求,響應內容爲上一步得到的明文消息內容(不能加引號,不能帶bom頭,不能帶換行符)
通過參數 msg_signature 對請求進行校驗
首先要把剛纔配置時隨機生成的 token, timestamp, nonce, msg_encrypt 進行 sha1 加密,這裏我們可以直接使用 npm 模塊 sha1 進行加密,然後判斷得到的 str 是否和 msg_signature 相等。
npm i sha1 --save
const sha1 = require('sha1');
const query = req.query;
const signature = query.msg_signature;
const timestamp = query.timestamp;
const nonce = query.nonce;
const echostr = query.echostr;
const tmpArr = [token, timestamp, nonce, echostr];
const tmpStr = sha1(tmpArr.sort().join(''));
if (tmpStr === signature) {
console.log('Check Success');
} else {
console.log('Check Failed');
}
解密 echostr 得到 消息明文msg 並返回
密文解密過程:
- 對剛纔生成的 AESKey 進行 base64 解碼
-
const EncodingAESKey = '21IpFqj8qolJbaqPqe1rVTAK5sgkaQ3GQmUKiUQLwRe'; let aesKey = Buffer.from(EncodingAESKey + '=', 'base64');
-
- 對 AESKey 進行 aes-256-cbc 解密
-
// 去掉 decipheredBuff 頭部的16個隨機字節和4個字節的 msg_len,截取 msg_len 長度的部分即爲msg,剩下的爲尾部的 receiveid const crypto = require('crypto'); let aesCipher = crypto.createDecipheriv("aes-256-cbc", aesKey, aesKey.slice(0, 16));
-
- 去掉補全的明文的頭部的16個隨機字節和4個字節的msg_len,截取msg_len長度的部分即爲msg,並返回msg進行驗證比對
-
aesCipher.setAutoPadding(false); let decipheredBuff = Buffer.concat([aesCipher.update(data, 'base64'), aesCipher.final()]); decipheredBuff = PKCS7Decoder(decipheredBuff); // 微信要求用 pkcs7進行補全 const len_netOrder_corpid = decipheredBuff.slice(16); const msg_len = len_netOrder_corpid.slice(0, 4).readUInt32BE(0); const msg = len_netOrder_corpid.slice(4, msg_len + 4).toString();
function PKCS7Decoder (buff) { var pad = buff[buff.length - 1]; if (pad < 1 || pad > 32) { pad = 0; } return buff.slice(0, buff.length - pad); }
-
回調url驗證失敗問題
驗證URL時,經常會碰到URL驗證失敗的問題,解決思路是藉助微信企業號接口調試工具: http://qydev.weixin.qq.com/debug,
具體各種坑詳見:URL校驗失敗的終極解決方法
使用說明:
- 選擇合適的接口。
- 系統會生成該接口的參數表,您可以直接在文本框內填入對應的參數值。(紅色星號表示該字段必填)
- 點擊檢查問題按鈕,即可得到相應的調試信息。
驗證URL對應的接口類型爲 "建立連接",接口列表選擇"測試回調模式"
2、設置白名單
在後臺主頁->服務商信息->基本信息->IP白名單->點擊修改按鈕,添加白名單IP列表
參數內容 | 說明 |
---|---|
白名單IP列表 | 服務商調用企業微信API時的合法IP列表,只有白名單內的IP才能正常調用企業微信API,修改後立即生效。支持“222.209.201.*” 這樣用通配符表示IP段;多個IP以英文分號;分隔 |
創建應用
創建完成之後,在“本地應用”欄可以看到該應用,點擊進入此應用,可以看到應用的SuiteId和SuiteSecret等信息,這些信息可用於調用第三方應用接口.
測試應用
應用創建成功後,服務商可以授權 10 個測試企業
從企業微信應用市場發起授權時,企業微信給剛纔應用設置的指令回調 url
發送一個 post 請求,比如:https://api.worktile.com/worktile?msg_signature=b99605616153ffbfbe6ebbb500bd211e67ed714d×tamp=1551076894&nonce=1551709703
,直接返回成功即可。
各個事件的回調,服務商在收到推送後都必須直接返回字符串 “success”,若返回值不是 “success”,企業微信會把返回內容當作錯誤信息。
app.post('/worktile', function (req, res) {
console.log('req.body', req.body);
res.send('success');
});
測試應用安裝成功之後,就可以通過企業微信——工作臺中測試應用
應用上線
已認證企業微信的服務商,可進入應用管理—點擊提交上線—勾選應用—提交上線。