如何使用明道配置企微消息服务接收消息

集成 系统集成企业微信私有部署  收藏
2 / 1293

* 注意事项:

* 配置步骤:

1.配置 webhook,参数【body 获取全文】 拿到对应的参数值,/PBP(封装业务流)请开启 API

  • 1.1 webhook 参数配置

image.png

  • 1.2 PBP 参数配置
    image.png
  1. 流程配置:
  • 入参配置以及参数释义:

image.png

  • 地址验证解析以及密文解析:
    在代码逻辑中:
    1.添加签名校验 防止信息篡改
    2.添加地址验证 还是应用消息信息判断,按实际解密后进行数据转换,消息也提业务
    (依据:验证地址发送 echostr ,不发送 msg_encrypt;地址证通过后才发 msg_encrypt 的 对应的 echostr 不发送。 )效果如下

image.png
image.png
image.png

  • 配置输出参数
    webhook
    image.png
    PBP
    image.png

整个流程到此配置结束。

python 解密整合

import base64
import string
import random
import hashlib
import time
import struct
from Crypto.Cipher import AES
import socket
import xmltodict
import json

key = base64.b64decode(input["key"]+"=")  
mode = AES.MODE_CBC
block_size = 32

def getSHA1(token, timestamp, nonce, msg):
    sortlist = [token, timestamp, nonce, msg]
    sortlist.sort()
    sha = hashlib.sha1()
    sha.update("".join(sortlist).encode())
    return sha.hexdigest()
def PKCS7Encoder_encode(text):
    text_length = len(text)
    # 计算需要填充的位数
    amount_to_pad = block_size - (text_length % block_size)
    if amount_to_pad == 0:
        amount_to_pad = block_size
    # 获得补位所用的字符
    pad = chr(amount_to_pad)
    return text + (pad * amount_to_pad).encode()

def PKCS7Encoder_decode(decrypted):
    pad = decrypted[-1]
    if pad<1 or pad >32:
        pad = 0
    return decrypted[:-pad]

def encrypt(text,receiveid):
    # 16位随机字符串添加到明文开头
    text = text.encode()
    text = get_random_str() + struct.pack("I", socket.htonl(len(text))) + text + receiveid.encode()
    # 使用自定义的填充方式对明文进行补位填充
    text = PKCS7Encoder_encode(text)
    # 加密    
    cryptor = AES.new(key,mode,key[:16])
    try:
        ciphertext = cryptor.encrypt(text)
        # 使用BASE64对加密后的字符串进行编码
        return base64.b64encode(ciphertext)
    except Exception as e:
        return  str(e)

def decrypt(text):
    try:
        cryptor = AES.new(key,mode,key[:16])
        # 使用BASE64对密文进行解码,然后AES-CBC解密
        plain_text = cryptor.decrypt(base64.b64decode(text))
    except Exception as e:
        return {"msg": "BASE64对密文进行解码:"+str(e,) ,"content":""}
    #try:
    pad =plain_text[-1]
    # 去除16位随机字符串
    content = plain_text[16:-pad]
    xml_len = socket.ntohl(struct.unpack("I",content[ : 4])[0])
    xml_content = content[4 : xml_len+4] 
    from_receiveid = content[xml_len+4:]
    return {"msg":'解析成功',"content":str(xml_content,'utf-8')}
    #json.dumps(xmltodict.parse())

def get_random_str():
    return str(random.randint(1000000000000000, 9999999999999999)).encode()

nsignature=getSHA1(input["token"],input["timestamp"],input["nonce"],input["msg_encrypt"])
content=input['echostr']
ismessage=False
if(len(content)==0):
  ismessage=True
  content=input['msg_encrypt']
result=decrypt(content)
if ismessage:
  result['content']=json.dumps(xmltodict.parse(result['content'],'utf-8'))
output={"签名":nsignature,"isTrue":nsignature==input['signature'],
"密文解密":result
}

nodejs 解密:

///企微消息解密
const crypto = require('crypto')
const EncodingAESKey = input.EncodingAESKey;
const aesMsg = input.echostr

function _decode(data, aesKeyEncoding) {
let aesKey = Buffer.from(aesKeyEncoding + '=', 'base64');
let aesCipher = crypto.createDecipheriv("aes-256-cbc", aesKey, aesKey.slice(0, 16));
aesCipher.setAutoPadding(false);
let decipheredBuff = Buffer.concat([aesCipher.update(data, 'base64'), aesCipher.final()]);
decipheredBuff = PKCS7Decoder(decipheredBuff);
let len_netOrder_corpid = decipheredBuff.slice(16);
let msg_len = len_netOrder_corpid.slice(0, 4).readUInt32BE(0);
const result = len_netOrder_corpid.slice(4, msg_len + 4).toString();
return result; // 返回一个解密后的明文-
}
function PKCS7Decoder (buff) {
var pad = buff[buff.length - 1];
if (pad < 1 || pad > 32) {
 pad = 0;
}
return buff.slice(0, buff.length - pad);
}

return { decryptMsg: _decode(aesMsg, EncodingAESKey) }

//// xml转json

const Xml2js = require('xml2js');
var xml={};
const Parser = new Xml2js.Parser({explicitArray: false, ignoreAttrs: false});
Parser.parseString(input.xml, function (err, data) {
   if (err) console.log(err);
   xml=data
});
output=xml