开启接收消息
一、准备工作
1、准备一个服务器,我用的是阿里云服务器ECS
2、申请一个域名,没有也没关系,我直接用的公网IP地址
3、申请一个企业微信号(需要营业执照)
二、验证URL函数(两步:验证signature和解密明文并返回)
1、企业微信通过GET传送四个参数signature1、timestamp、nonce、echostr
2、通过sha1函数把token、timestamp、nonce、echostr按字母顺序排列,生成一个signature2,与signature1对比,如果一样,即向下执行3
3、解密GET到的echostr(密文),得到明文消息:
- 用base64解码EncodingAESKey,得到32字节长的AESKey
AESKey = base64.b64decode(sEncodingAESKey + "=")
- 用base64解码echostr(密文)得到text
text = base64.b64decode(echostr)
- 用上文得到的AESKey 和AES-CBC模式解密text
cryptor = AES.new(self.key, self.mode, self.key[:16])
plain_text = cryptor.decrypt(base64.b64decode(text))
- 明文字符串由16个字节的随机字符串、4个字节的msg长度、明文msg和receiveid拼接组成。其中msg_len为msg的字节数,网络字节序;
rand_msg = random(16B) + msg_len(4B) + msg + receiveid
plain_text大概长这样:
5. 获取msg的长度
xml_len = socket.ntohl(struct.unpack("I", plain_text[16: 20])[0])
-6. 分别切取msg和receiveid,对比receiveid和企业ID,如果一样,返回 msg,至此开启接收消息成功!!!
msg大概长这样**:
接收消息的逻辑(三步:1获得明文,组合成xml消息体,2把消息体加密,3把加密的消息体做成接口并返回)
1、接收消息是POST请求,首先通过request获得消息体
xmltext=request.stream.read()
2、提取出xml数据包中的加密消息
xml_tree = ET.fromstring(xmltext)
encrypt = xml_tree.find("Encrypt").text
3、通过sha1函数把token、timestamp、nonce、encrypt 按字母顺序排列,生成一个signature2,与signature1对比,如果一样,即向下执行4(与验证URL函数的第2步一样,看来签名的验证非常重要)
4、解密提取出来的encrypt ,得到明文消息(与验证URL函数的第3步一样):
5、用xml.etree.cElementTree建立element文件
xml_tree = ET.fromstring(sMsg)
这个element文件包含以下消息:消息发送者,消息接收者,消息发送时间,消息内容,消息ID,agent ID
6、用element文件提取的内容重新组合成一个XML消息体
7、把XML消息体加密:
- 随机生成一个16位字符窜
random_str = str(random.randint(1000000000000000, 9999999999999999)).encode()
- 16位随机字符串添加到明文开头
text2 = random_str + struct.pack("I", socket.htonl(len(text1))) + XML消息体.encode() + receiveid.encode()
- 使用自定义的填充方式对明文进行补位填充
- 用AESKey 和AES-CBC模式加密第三部返回的结果,得到encrypt
- 验证签名signature,如果没有错,进行下一步
ret, signature = sha1.getSHA1(self.m_sToken, timestamp, sNonce, encrypt)
6.提供提取消息格式中的密文及生成回复消息格式的接口,并返回这个接口