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

    写完了,快乐呀。哈哈

  • 相关阅读:
    npm 一些常用的命令
    Angular Encapsulation
    隐藏scrollbar
    Vue生命周期详解(1)- 单个组件
    如何自己制作iconfont
    day07-2018-10--25 深浅拷贝
    day06-2018-10--24 小数据池和编码
    day05-2018-10--23 字典
    day04-2018-10--22python基础
    day03-2018-10-19-python基础
  • 原文地址:https://www.cnblogs.com/roadwide/p/10588063.html
Copyright © 2020-2023  润新知