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')
參考文章: