文章目录
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请求携带的参数。下一步我们来仔细剖析里面的细节。
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)。
下面是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解析模块,提取要用到的参数。