token验证的意义
在看了别人的代码之后对token加密有了些理解了。但又觉得很鸡肋。第一次验证服务器的时候我在那弄了半天的验证其实不写也可以验证成功,只要直接返回echostr这个字段就行了。微信的服务器只检查我的服务器返回的值和他想要的值是否一样,来判断是否验证成功,但是验证的过程是我在自己的服务器上做的,我可以不验证,直接返回他想要的值。虽然这样违背安全的目的。
微信这个token验证应该不只是第一次验证服务器时要用,应该是每次接收消息都要验证是不是从微信服务器发送过来的。第一次是get的请求,接收消息是post的请求。但无论是哪种,都会是一get的形式和url来访问。所以哪怕是接收消息,也应该是验证是否是微信服务器所发送来的。
接收和发送消息
通过判断是get还是post来分辨是第一次验证还是接收的消息。如果时post就解析发送过来的信息的xml(这里用到了xmltodict这个包,后续学一下)。
xml消息的结构如下:
<xml> <ToUserName><![CDATA[gh_866835093fea]]></ToUserName> <FromUserName><![CDATA[ogdotwSc_MmEEsJs9-ABZ1QL_4r4]]></FromUserName> <CreateTime>1478317060</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[你好]]></Content> <MsgId>6349323426230210995</MsgId> </xml>
解析post包可以获得用户发送过来的消息,而对post包的返回值就是微信公众号对用户的回复,同样时xml形式。发来的消息有不通的type,可以采取不同的回复形式等等。
以下是学习别人代码后,我写的代码。其中对于用户发送的消息没有进行token的验证,只是学习收发消息,没有写那么严密。
from flask import Flask,request import hashlib import xmltodict import time app = Flask(__name__) @app.route('/wx', methods=["GET", "POST"]) def getinput(): if (request.method == "GET"): # 表示是第一次接入微信服务器的验证 signature=request.args.get('signature') timestamp=request.args.get('timestamp') nonce=request.args.get('nonce') token = "maluguang" list = [token, timestamp, nonce] list.sort() sha1 = hashlib.sha1() sha1.update(list[0].encode('utf-8')) sha1.update(list[1].encode('utf-8')) sha1.update(list[2].encode('utf-8')) hashcode = sha1.hexdigest() echostr = request.args.get("echostr") if hashcode == signature: return echostr else: return "" elif request.method == "POST": # 表示微信服务器转发消息过来 xml_str = request.data if not xml_str: return"" # 对xml字符串进行解析 xml_dict = xmltodict.parse(xml_str) xml_dict = xml_dict.get("xml") # 提取消息类型 msg_type = xml_dict.get("MsgType") if msg_type == "text": # 表示发送的是文本消息 # 构造返回值,经由微信服务器回复给用户的消息内容 resp_dict = { "xml": { "ToUserName": xml_dict.get("FromUserName"), "FromUserName": xml_dict.get("ToUserName"), "CreateTime": int(time.time()), "MsgType": "text", "Content": "you say:" + xml_dict.get("Content") } } # 将字典转换为xml字符串 resp_xml_str = xmltodict.unparse(resp_dict) # 返回消息数据给微信服务器 return resp_xml_str else: resp_dict = { "xml": { "ToUserName": xml_dict.get("FromUserName"), "FromUserName": xml_dict.get("ToUserName"), "CreateTime": int(time.time()), "MsgType": "text", "Content": "Dear I Love you so much" } } resp_xml_str = xmltodict.unparse(resp_dict) # 返回消息数据给微信服务器 return resp_xml_str if __name__ == '__main__': app.run(port='80')
参考文章: