使用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已经做出来了,后面要是用就可以在这基础上进行更改了。不过我也不是为了用它才写这个的,就是想学学微信公众号的开发,写点东西练练手。

写完了,快乐呀。哈哈

使用flask搭建微信公众号:实现签到功能

以上是使用flask搭建微信公众号:实现签到功能的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>