使用flask搭建微信公眾號:實現簽到功能


終於到了實戰階段。用微信公眾號實現一個簡單的簽到功能。

前情提要:

微信公眾號token驗證失敗

使用flask搭建微信公眾號:完成token的驗證

使用flask搭建微信公眾號:接收與回復消息

程序邏輯如下圖

發起簽到

生成"隨機數.txt"文件,並將隨機數返回作為簽到碼,將簽到碼返回給發起簽到的用戶

def gensign():
    sign_number=random.randint(1000,9999)
    f = open(str(sign_number)+'.txt','w')
    f.close()
    return str(sign_number)

簽到

用戶發送"簽到 簽到碼 用戶名"給公眾號(各項之間用一個空格分開)。服務器接收到信息后將用戶名寫入簽到文件中,並返回是否簽到成功

def sign(sign_number,username):
    if(os.path.exists(sign_number+'.txt')):
        with open(sign_number+'.txt','a') as f:
            f.write(username+'\n')
        return "簽到成功"
    elif(os.path.exists(sign_number)):
        return "已超出簽到時間"
    else:
        return "簽到失敗"

關閉簽到

關閉簽到是為了給簽到設定期限,由用戶選擇何時關閉簽到。我這里的關閉簽到就是把后綴名的txt給刪掉。發送"關閉 簽到碼"給公眾號(各項之間用一個空格分開)。即可關閉簽到

def closesign(sign_number):
    if(os.path.exists(sign_number+'.txt')):
        os.rename(sign_number+'.txt',str(sign_number))

查看簽到

發送"查看 簽到碼"給公眾號(各項之間用一個空格分開)即可查看某個簽到的簽到情況。這里發送的是簽到碼,所以只有在關閉簽到后才能查看(當然,發帶.txt的也能)。就是把讀取某個簽到文件的內容返回給查看簽到的用戶即可。

所有代碼

from flask import Flask,request
import hashlib
import xmltodict
import time
import random
import os

def gensign():
    sign_number=random.randint(1000,9999)
    f = open(str(sign_number)+'.txt','w')
    f.close()
    return str(sign_number)

def closesign(sign_number):
    if(os.path.exists(sign_number+'.txt')):
        os.rename(sign_number+'.txt',str(sign_number))

def sign(sign_number,username):
    if(os.path.exists(sign_number+'.txt')):
        with open(sign_number+'.txt','a') as f:
            f.write(username+'\n')
        return "簽到成功"
    elif(os.path.exists(sign_number)):
        return "已超出簽到時間"
    else:
        return "簽到失敗"

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":
            # 表示發送的是文本消息
            # 構造返回值,經由微信服務器回復給用戶的消息內容
            userinput=xml_dict.get("Content")
            if(userinput=='發起簽到'):
                sign_number=gensign()
                resp_dict = {
                    "xml": {
                        "ToUserName": xml_dict.get("FromUserName"),
                        "FromUserName": xml_dict.get("ToUserName"),
                        "CreateTime": int(time.time()),
                        "MsgType": "text",
                        "Content": "您的簽到碼為" +sign_number
                    }
                }
                # 將字典轉換為xml字符串
                resp_xml_str = xmltodict.unparse(resp_dict)
                # 返回消息數據給微信服務器
                return resp_xml_str
            else:
                userinput=xml_dict.get("Content")
                if("關閉" in userinput):
                    try:
                        msglist=userinput.split(" ")
                        sign_number=msglist[1]
                        closesign(sign_number)
                        resp_dict = {
                            "xml": {
                                "ToUserName": xml_dict.get("FromUserName"),
                                "FromUserName": xml_dict.get("ToUserName"),
                                "CreateTime": int(time.time()),
                                "MsgType": "text",
                                "Content": "成功關閉簽到" +sign_number
                            }
                        }
                        # 將字典轉換為xml字符串
                        resp_xml_str = xmltodict.unparse(resp_dict)
                        # 返回消息數據給微信服務器
                        return resp_xml_str
                    except:
                        return "success"
                if("簽到" in userinput):
                    try:
                        msglist=userinput.split(' ')
                        sign_number=msglist[1]
                        username=msglist[2]
                        return_msg=sign(sign_number,username)
                        resp_dict = {
                            "xml": {
                                "ToUserName": xml_dict.get("FromUserName"),
                                "FromUserName": xml_dict.get("ToUserName"),
                                "CreateTime": int(time.time()),
                                "MsgType": "text",
                                "Content": username+return_msg+sign_number
                            }
                        }
                        # 將字典轉換為xml字符串
                        resp_xml_str = xmltodict.unparse(resp_dict)
                        # 返回消息數據給微信服務器
                        return resp_xml_str
                    except:
                        return "success"
                if("查看" in userinput):
                    try:
                        msglist=userinput.split(' ')
                        sign_number=msglist[1]
                        if(os.path.exists(sign_number)):
                            with open(sign_number,'r') as f:
                                data=f.read();
                        else:
                            data='打開簽到文件失敗'
                        resp_dict = {
                            "xml": {
                                "ToUserName": xml_dict.get("FromUserName"),
                                "FromUserName": xml_dict.get("ToUserName"),
                                "CreateTime": int(time.time()),
                                "MsgType": "text",
                                "Content": sign_number+'簽到情況為\n'+data
                            }
                        }
                        # 將字典轉換為xml字符串
                        resp_xml_str = xmltodict.unparse(resp_dict)
                        # 返回消息數據給微信服務器
                        return resp_xml_str
                    except:
                        return "success"
        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')

運行截圖

一些漏洞和缺陷

1.【大漏洞】沒有對簽到的控制驗證權限,任何人只要發送正確的命令都可以操控簽到,關閉簽到,查看簽到等。可能會有人趁此搗亂。其實應該是只有發起簽到的人有權力操縱的

2.每次都會寫返回的xml的同樣的東西,應該可以省略然后只改不一樣的部分的。后面再看看

3.代碼很丑,一堆if可能效率還很低

4.異常處理也沒有管那么多。可能會有意料之外的錯誤

5.發送的消息未經token驗證,這個是懶得寫,反正又不是投入生產環境的

6.生成的隨機數可能會重復而產生問題

7.一個微信號可以一直簽到,可以替任何人簽到,沒有進行微信號和簽到人的綁定來確定簽到的唯一性

應該還有很多問題,暫時就想到這么多了。不過就算一堆問題也不重要,重要的是這個prototype已經做出來了,后面要是用就可以在這基礎上進行更改了。不過我也不是為了用它才寫這個的,就是想學學微信公眾號的開發,寫點東西練練手。

寫完了,快樂呀。哈哈


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM