[基于Python的微信公众号后台开发:2]文字消息的接收与解密

发布于:2022-12-23 ⋅ 阅读:(450) ⋅ 点赞:(0)

1、服务器安装pycryptodome

安装命令

pip install pycryptodome

2、下载微信官方提供的解密SDK

链接为 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Message_encryption_and_decryption_instructions.html
因为官方提供的SDK是Python2版本的,源码有些语句不兼容于Python3,需要做修改,这边提供一个Github大佬修改好的SDK,链接为 https://github.com/chenjianjx/wechat-encrypt-python3

3、上传SDK到服务器

上传WXBizMsgCrypt.py和ierror.py这两个文件即可,要注意的是,这两个文件要与主程序launch.py在同一个目录下

4、开始测试

以下为本次测试launch.py的代码

from flask import Flask, render_template, url_for, redirect, request, abort
from gevent import pywsgi
import hashlib
from WXBizMsgCrypt import WXBizMsgCrypt
from xml.dom.minidom import parseString

flask_app = Flask(__name__)


@flask_app.route('/', methods=["GET", "POST"])
def home():
    # 公众号基本的参数
    token = "[此处替换Token]"
    appid = "[此处替换AppID]"
    encodingaeskey = "[此处替换encodingAESKey]"
    # 微信服务器发来的三个get参数
    signature = request.args.get("signature")
    timestamp = request.args.get("timestamp")
    nonce = request.args.get("nonce")
    # 加进同一个列表里
    list1 = [token, timestamp, nonce]
    # 排序
    list1.sort()
    # 把列表转换成字符串
    str1 = "".join(list1)
    # 生成sha1值
    sha1_str = hashlib.sha1(str1.encode("utf-8")).hexdigest()
    # 与signature参数比对
    # 若不一致
    if signature != sha1_str:
        # 被认定为非微信服务器发来的get请求
        # 返回403拒接请求
        abort(403)
    # 若一致
    else:
        # 若为post请求则认定为有消息从微信服务器转发过来
        if request.method == "POST":
            # 获取post过来的byte数据
            # 为密文
            encrypted_bytes = request.data
            if encrypted_bytes:
                # 获取openid参数和msg_signature参数
                openid = request.args.get("openid")
                msg_signature = request.args.get("msg_signature")
                # 用微信官方提供的SDK解密,附带一个错误码和生成明文
                keys = WXBizMsgCrypt(token, encodingaeskey, appid)
                ierror, decrypted_bytes = keys.DecryptMsg(encrypted_bytes, msg_signature, timestamp, nonce)
                # 若错误码为0则表示解密成功
                if ierror == 0:
                    # 对XML进行解析
                    dom_data = parseString(decrypted_bytes).documentElement
                    # XML中Content标签的内容为消息内容
                    # 提取Content
                    content = dom_data.getElementsByTagName("Content")[0].childNodes[0].data
                    print(encrypted_bytes)
                    print(decrypted_bytes)
                    print(content)

                return "200"
            else:
                abort(400)


if __name__ == '__main__':
    # 此配置解决WSGI报错问题
    server = pywsgi.WSGIServer(('0.0.0.0', 5000), flask_app)
    server.serve_forever()
    

修改好或上传好launch.py之后跑起来

5、发送消息到公众号

笔者用手机给公众号发了一个“哈”字,消息发出后看回SSH窗口,如图,从上往下红框1到4分别是密文XML、明文XML、经过解密后消息内容和post请求携带的参数。下一步我们来仔细剖析里面的细节。
2-1.png

6、测试解密:把所有参数套入官方给的Sample.py文件后运行

如图,我在本地环境(前提是安装好pycryptodome库和把WXBizMsgCrypt.py和ierror.py放在旁边方便导入的),根据官方给的Sample.py解密实例文件,然后分别把encodingAESKey密钥(红框1)、Token(红框2)、AppID(红框4)套上,然后把密文套上from_xml(红框7),nonce、timestamp、msg_sign则在post请求参数之中,也把它们套上(红框3、5、6)。
2-2.png
2-3.png
下面是Sample.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#########################################################################
# Author: jonyqin
# Created Time: Thu 11 Sep 2014 03:55:41 PM CST
# File Name: demo.py
# Description: WXBizMsgCrypt 使用demo文件
#########################################################################
from WXBizMsgCrypt import WXBizMsgCrypt

if __name__ == "__main__":
    """ 
   1.第三方回复加密消息给公众平台;
   2.第三方收到公众平台发送的消息,验证消息的安全性,并对消息进行解密。
   """
    encodingAESKey = "[此处替换encodingAESKey]"
    token = "[此处替换Token]"
    nonce = "[此处替换nonce]"
    appid = "[此处替换AppID]"

    # 测试解密接口
    timestamp = "[此处替换timestamp]"
    msg_sign = "[此处替换msg_sign]"

    from_xml = """[此处替换密文]"""
    decrypt_test = WXBizMsgCrypt(tkFCX27abbmco5fXPq7WliK26jUQeL0kDJ5izD5hWoken, encodingAESKey, appid)
    ret, decryp_xml = decrypt_test.DecryptMsg(from_xml, msg_sign, timestamp, nonce)
    print(ret, decryp_xml)

7、接下来我们来剖析一下XML的内容

如图,经过上一步运行会得到解密后的明文,把密文XML和明文XML分别拷贝下来对比。上面的是密文,可以看到只有ToUserName和Encrypt两个标签,前者为接收消息的公众号账号,后者为经过微信服务器加密过后的密文。然而经过解密,得到的除了ToUserName,还有FromUserName、CreateTime、MsgType、Content、MsgId,它们分别是发送者的OpenID、时间码、消息类型、消息内容的bytes格式、消息ID,得到的明文方便我们后续调用XML解析模块,提取要用到的参数。
2-4.png

本文含有隐藏内容,请 开通VIP 后查看