添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

注册的逻辑

  1. 注册需要的参数用户名,密码等,主要是图片验证码等输入
  2. 输入图片验证码之后,点击获得验证码,这时候要验证图片验证码的正确性
  3. 图片验证码正确才会发生短信,用户收到短信之后,输入后,点击注册就可以把数据写入数据库。

图片验证码的作用是防止短信发送的浪费,但是背后真的那么简单吗?想多了,下面讲一下细节。这是代码===>

class RegisterForm(forms.Form):
    username = forms.CharField(label='用户名', max_length=20, min_length=5,
                               error_messages={"min_length": "用户名长度要大于5",
                                               "max_length": "用户名长度要小于20",
                                               "required": "用户名不能为空"}
    password = forms.CharField(label='密码', max_length=20, min_length=6,
                               error_messages={"min_length": "密码长度要大于6",
                                               "max_length": "密码长度要小于20",
                                               "required": "密码不能为空"}
    password_repeat = forms.CharField(label='确认密码', max_length=20, min_length=6,
                                      error_messages={"min_length": "密码长度要大于6",
                                                      "max_length": "密码长度要小于20",
                                                      "required": "密码不能为空"}
    mobile = forms.CharField(label='手机号', max_length=11, min_length=11,
                             error_messages={"min_length": "手机号长度有误",
                                             "max_length": "手机号长度有误",
                                             "required": "手机号不能为空"})
    sms_code = forms.CharField(label='短信验证码', max_length=6, min_length=6,
                               error_messages={"min_length": "短信验证码长度有误",
                                               "max_length": "短信验证码长度有误",
                                               "required": "短信验证码不能为空"})
    # 上面是简单清洗,下面是再次清洗
    def clean_username(self):
        check mobile
        :return:
        uname = self.cleaned_data.get('username')  # 拿到数据
        if Users.objects.filter(username=uname).exists():  # 数据库里面判断是不是有
            raise forms.ValidationError("用户名已注册,请重新输入!")  # exists 有就返回false没有就返回Ture
        return uname
    def clean_mobile(self):
        tel = self.cleaned_data.get('mobile')  # 获取手机号
        if not re.match(r"^1[3-9]\d{9}$", tel):
            raise forms.ValidationError("手机号码格式不正确")
        if Users.objects.filter(mobile=tel).exists():
            raise forms.ValidationError("手机号已注册,请重新输入!")
        return tel
    def clean(self):
        # 继承父类的clean方法, 获取提交的表单数据
        cleaned_data = super().clean()
        passwd = cleaned_data.get('password')
        passwd_repeat = cleaned_data.get('password_repeat')
        # 密码判断
        if passwd != passwd_repeat:
            raise forms.ValidationError("两次密码不一致")
        # 拿到手机号
        tel = cleaned_data.get('mobile')
        # 拿到短信验证码
        sms_text = cleaned_data.get('sms_code')  # 字典类型通过键取值
        # 建立redis连接
        redis_conn = get_redis_connection(alias='verify_codes')
        # 创建用户输入的手机号标志
        sms_fmt = "sms_{}".format(tel).encode('utf8')
        # 从数据库里面拿出手机号,名字是一样的
        real_sms = redis_conn.get(sms_fmt)  # 那边的数据也是这样写入数据库的,不是只写了手机号进数据库。
        # 判断是否一致
        if (not real_sms) or (sms_text != real_sms.decode('utf8')):
            raise forms.ValidationError("短信验证码错误")

首先图片验证码已开始加载的时候放在哪里?当用户点入注册页面,会自动生成图片验证码,并且保存在redis中,为了保证图片key和其他用户的不一致,前端会传一个参数uuid,这样redis里面就保存了一个这样的键指对了。

img_aksjdknwas(uuid): 9821(图片验证码)
class ImageCode(View):
    def get(self, request, image_code_id):
        text, image = captcha.generate_captcha()
        conn_redis = get_redis_connection('verify_codes')
        img_key = "img_{}".format(image_code_id).encode('utf8')
        conn_redis.setex(img_key, constants.IMAGE_CODE_REDIS_EXPIRES, text)
        logger.info("Image code:{}".format(text))
        return HttpResponse(content=image, content_type='image/jpg')

那什么时候拿出来呢?当然是点击注册的时候要验证,就要拿出来。

form = forms.CheckImgCodeForm(data=dict_data)

下面是验证图片验证码的正确性,要去redis里面查出来,同时生成一个手机号60s内不能再次发生的标志保存进redis数据库。

class CheckImgCodeForm(forms.Form):
    check image code
    mobile = forms.CharField(max_length=11, min_length=11, validators=[mobile_validator, ],
                             error_messages={"min_length": "手机号不能为空"




    
,
                                             "max_length": "手机号不能为空",
                                             "required": "手机号不能为空",
    image_code_id = forms.UUIDField(error_messages={"required": "图片UUID不能为空"})
    text = forms.CharField(max_length=4, min_length=4,
                           error_messages={"min_length": "图片验证码长度有误",
                                           "max_length": "图片验证码长度有误",
                                           "required": "图片验证码不能为空",
    def clean(self):
        cleaned_data = super().clean()
        image_text = cleaned_data.get('text')
        mobile_num = cleaned_data.get('mobile')
        image_uuid = cleaned_data.get('image_code_id')
        if Users.objects.filter(mobile=mobile_num).count():
            raise forms.ValidationError("手机号已经注册,请重新输入!")
        # 确保settings.py文件中有配置redis CACHE
        # Redis原生指令参考 http://redisdoc.com/index.html
        # Redis python客户端 方法参考 http://redis-py.readthedocs.io/en/latest/#indices-and-tables
    # 1.获取图片验证码
        try:
            con_redis = get_redis_connection(alias='verify_codes')
        except Exception as e:
            raise forms.ValidationError("未知错误")
        img_key = "img_{}".format(image_uuid).encode('utf8')
        real_image_code_origin = con_redis.get(img_key)
        real_image_code = real_image_code_origin.decode('utf-8') if real_image_code_origin else None
        con_redis.delete(img_key)
    # 2. 验证手机号
        if (not real_image_code) or image_text.upper() != real_image_code:
            raise forms.ValidationError("图片验证失败")
    # 3.检查是否在60s内有发送记录
        sms_flag_fmt = "sms_flag_{}".format(mobile_num).encode('utf8')
        sms_flag = con_redis.get(sms_flag_fmt)
        if sms_flag:
            raise forms.ValidationError("获取手机短信验证码过于频繁")
class CheckUsernameView(View):
    GET username/(?<username>\w{5,20})/
    def get(self, request, username):
        count = Users.objects.filter(username=username).count()
        data = {
            'username': username,
            'count': count,
        return to_json_data(data=data)
class CheckMobileView(View):
    GET mobiles/(?P<mobile>1[3-9]\d{9})/
    def get(self, request, mobile):
        # count = User.objects.filter(mobile=mobile).count()
        data = {
            'mobile': mobile,
            'count': Users.objects.filter(mobile=mobile).count()
        return to_json_data(data=data)

上面的代码是检查数据库中是否有一样的手机号和用户名。

下面可以发送短信验证码了吧,烦死了!!!🤗🤗
生产短信验证码,保存在redis数据库里,这里保存的话用到了redis的pipeline技术和redis进行交互。然后通知平台进行发送(这里用了celery技术)。

class SmsCodesView(View):
    1,获取参数
    2,验证参数
    3,发送信息
    4,保存短信验证码
    5,返回给前端
    POST /sms_codes/
    -检查图片验证码是否正确
    -检查是否60秒有记录
    -生成短信验证码
    -发送短信
    # 1. 获取参数,
    def post(self, request):   # 表单
        json_data = request.body  # body里面包含的是什么,body就是前台给到后台的数据,ajax发过来的数据
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])  # 报错罢了
        dict_data = json.loads(json_data.decode('utf8'))
        form = forms.CheckImgCodeForm(data=dict_data)
    # 2. 校验参数
        if form.is_valid():
            # 获取手机号
            mobile = form.cleaned_data.get('mobile')
            # 创建短信验证码内容
            sms_num = "%06d" % random.randint(0, 999999)
            # 1.将短信验证码保存到数据库
            # 确保settings.py文件中有配置redis CACHE
            # Redis原生指令参考 http://redisdoc.com/index.html
            # Redis python客户端 方法参考 http://redis-py.readthedocs.io/en/latest/#indices-and-tables
            con_redis = get_redis_connection(alias='verify_codes')
            # 创建一个在60秒内是否发送记录的标记
            sms_flag_fmt = "sms_flag_{}".format(mobile).encode('utf8')
            # 创建保存短信验证码的标记key
            sms_text_fmt = "sms_{}".format(mobile).encode('utf8')
            # 节省通讯次数
            pl = con_redis.pipeline()  # redis管道技术
            try:
                pl.setex(sms_flag_fmt, constants.SEND_SMS_CODE_INTERVAL, 1)  # 60秒的标志,1号模板
                pl.setex(sms_text_fmt, constants.IMAGE_CODE_REDIS_EXPIRES, sms_num)  # 把短信验证码保存进去了
            # 通知redis执行命令
                pl.execute()
            except Exception as e:
                logger.debug('redis 执行异常{}'.format(e))
                return to_json_data(errno=Code.UNKOWNERR, errmsg=error_map[Code.UNKOWNERR])
            # 2.发送短信 通知平台
            logger.info('SMS code:{}'.format(sms_num))
            expires = constants.SMS_CODE_REDIS_EXPIRES
            sms_tasks.send_sms_code.delay(mobile, sms_num, expires, constants.SMS_CODE_TEMP_ID)
            return to_json_data(errno=Code.OK, errmsg="短信验证码发送成功")
        else:
            # 定义错误信息列表
            err_msg_list = []
            for item in form.errors.get_json_data().values():
                err_msg_list.append(item[0].get('message'))
            err_msg_str = '/'.join(err_msg_list)
            return to_json_data(errno=Code.PARAMERR, errmsg=err_msg_str)

用户收到短信验证码后填入就大概注册完成了。

pipeline是啥?

https://blog.csdn.net/weixin_43673156/article/details/123981998

celery是什么?

celery异步任务

sms_tasks.send_sms_code.delay(mobile, sms_num, expires, constants.SMS_CODE_TEMP_ID)

celery队列

Celery 是一个 基于python开发的分布式异步消息任务队列,通过它可以轻松的实现任务的异步处理, 如果你的业务场景中需要用到异步任务,就可以考虑使用celery.

使用场景:

1.你想对100台机器执行一条批量命令,可能会花很长时间 ,但你不想让你的程序等着结果返回,而是给你返回 一个任务ID,你过一段时间只需要拿着这个任务id就可以拿到任务执行结果, 在任务执行ing进行时,你可以继续做其它的事情。

2.你想做一个定时任务,比如每天检测一下你们所有客户的资料,如果发现今天 是客户的生日,就给他发个短信祝福

Celery原理:

Celery 在执行任务时需要通过一个消息中间件来接收和发送任务消息,以及存储任务结果, 一般使用rabbitMQ or Redis 或者是数据库来存放消息的中间结果

Celery优点:

简单:一旦熟悉了celery的工作流程后,配置和使用还是比较简单的
高可用:当任务执行失败或执行过程中发生连接中断,celery 会自动尝试重新执行任务
快速:一个单进程的celery每分钟可处理上百万个任务
灵活: 几乎celery的各个组件都可以被扩展及自定制
在这里插入图片描述
在这里插入图片描述

一、流程分析: 1.用户在项目前端,输入手机号,然后点击【获取验证码】,将手机号发到post到后台。 2.后台验证手机号是否合法,是否已被占用,如果通过验证,则生成验证码,并通过运行脚本,让运营商向该手机号,发送验证码,如果没通过验证,则返回错误息 3.用户收到验证码以后,再次将所有息post到后台。 4.后台验证各个数据,通过验证则完成实名制认证,如果没通过则返回错误息。 总结,一次实名验证,需要两次ajax+post 二、对接商: 1.在云片网端: 1.注册云片网 地址:https://www.yunpian.com/ 后台管理控制台页面:其中最重要的息是APIKEY 移动飞代发服务数据库编程接口说明 移动飞代发服务接口使用数据库记录查询方式实现,支持MS SQL及Access数据库,只用到一个FetionTb表进行交换,运行之前请先创建好FetionTb表,然后配置SYSSET.INI文件的"数据库类型"及"连接字符串"。 一、FetionTb表结构字段含意如下: id字段(自动编号):主键,标识不同的命令记录 Com字段(字符型,长20):命令字符串,支持四个命令是"发送"、"添加好友"、"好友列表"、"接收" myMNo字段(字符型,长20):发送手机的号码 myMPass字段(字符型,长30):发送手机的飞密码 toMNo字段(字符型,长250):接收手机的号码,多个接收号码可以用逗号","分开 (是飞好友才会发送成功,当与发送手机号相同时就会发给自己了) Msg字段(字符型,长250):内容,不能超过移动要求的长度 reok字段(数字型):命令记录处理状态,有4个值表示,-1=正在处理中,0=等待处理中,1=处理完成,2=已经提取处理结果,10=收到的 retxt字段(备注型):处理完成后返回的息 addTime字段(时间型):记录加入时间或最后处理时间 mtype字段(字符型,长20):可以是任意字符,客户程序可用来自行定义命令执行区分标志 二、客户程序发送流程: 1)客户程序将命令记录(如"发送")插入表(注意reok字段要等于0,retxt字段要为空) SQL语句例:INSERT FetionTb(Com,myMNo,myMPass,toMNo,Msg,reok,retxt,addTime,mtype) VALUES('发送','13700000008','888888','13600000088','你好!',0,'',getdate(),'1234') 2)客户程序定时查询执行结果,主要查reok字段是否变为1 SQL语句例:SELECT retxt from FetionTb where reok=1 and myMNo='13700000008' and toMNo='13600000088' and mtype='1234' 当结果不为空时说明记录执行完成 3)客户程序查到命令结果后,还要把reok字段改为2,以通知服务程序命令完成,可以删除此记录了 SQL语句例:UPDATE FetionTb SET reok=2 where reok<>0 and myMNo='13700000008' and toMNo='13600000088' and mtype='1234' 注:如果不修改reok字段改为2,服务程序也会在10分钟至1个半小时左右删除已经执行完成的记录,如要保存发送记录,请自行记录到别的表。 对于"添加好友"命令,Msg字段可以为空串;"好友列表"命令toMNo字段与Msg字段可以为空串 三、好友列表返回结果说明:好友之间以逗号","分开,每个好友又以"|"分开名称与手机号码,客户程序可以把字符串处理分割成列表。 例如:"张三|13788888881,李四|1360000002" 四、接收说明:“接收”是服务程序收到的当前号码,reok字段为10,用户以这个为条件查收,查收后请把reok字段改为2,或直接删除。 附件: 数据库审计系统需求说明 序号 指标项 具体要求 1 硬件指标 标准机架式设备,不少于 6个1000M电口,不少于 2个SFP光口(带SFP模块), 具备独立的管理口和 HA 口;可用磁盘空间不小于 2T;吞吐能力》2000M峰值处 理能力》18000条/秒,根据任意sql条件查询性能》2000万条/秒;日志存储量 > 6亿条;双冗余电源。 2 工作模式 旁路镜像模式部署,不影响数据库性能和网络架构;支持 IPV6环境部署和IPV6 环境下数据库的审计;支持分布式部署,管理中心可实现统一配置、统一报表、 统一查询。 管理中心和探测器都可存储审计数据,实现大数据环境下磁盘空间的有效利用和 扩展;管理中心和探测器直接的数据传输速率、时间、端口都可自定义。 3 协议支持 支持主流数据库: Oracle、SQLServer、Mysql、DB2 infomix、Sybase、CACH、 达梦、人大金仓、神舟 Oscar、南大通用 GBASE数据仓库teradata。 支持主流业务协议: TeInet、SMTP POP3 DCOM 4 审计内容 审计日志包括账号、 SQL语句、表、字段、存储过程、客户端工具、 IP、MAC实 例名、主机名等条件。 支持双向审计,特别是返回字段和结果、执行状态、返回行数、执行时长等内容, 并能够根据返回结果设置审计策略,要求在不连接被审计数据库情况下完成。 支持HTTP请求审计,提取URL POST/GETf直、cookie、操作系统类型、浏览器 类型、原始客户端IP、MAC地址、提交参数等。 可与堡垒主机进行联动,实现用户息的定位。 5 智能发现 自动识别流量中存在的数据库,也可通过扫描发现网络中的数据库。 支持定期自动扫描数据库漏洞和不安全配置,提供漏洞扫描报告。 6 运维审计 支持tel net、ftp、SSH协议及其他私有协议的旁路会话审计;会话审计日志应含 源IP、目的IP、会话起始时间、会话结束时间、连接时长、会话总流量等维度。 支持数据库协议解析成会话形式,并支持一键关联到具体的 SQL操作会话。 支持根据目的IP、目的端口、源IP及时间范围对会话进行检索。 7 模型分析 可智能学习数据库的访问行为建立模型。 可通过行为轨迹图方式展示数据库访问行为。 可基于账号、IP地址、访问权限、客户端工具等维度对行为模型做钻取分析、变 更分析,对学习的安全基线以外的行为自动智能的进行告警。 可以自动对比不冋时期的行为模型,以区分其审计日志数趋势、用户、 IP地址、 工具、访问权限的差异情况。 8 规则分析 支持账号、IP地址、MAC地址、操作类型、返回行数、执行时 、表、字段、主 数据库审计系统需求说明全文共2页,当前为第1页。 数据库审计系统需求说明全文共2页,当前为第1页。 机名、操作系统名、关联表数,实现对敏感息的精细监控。 支持基于返回结果集大小、返回内容、具体报文内容的细粒度审计规则。 内置高危SQL查询和注入、远程命令执行、跨站脚本攻击、 FTP和telnet高危指 令等审计规则不少于 300种。 规则可支持导入、导出、优先级调整、分组、批量加载等。 9 白名单 支持用户名、操作类型、IP地址、客户端工具、系统用户名、主机名、 MAC地址、 SQL语句等条件设置白名单,条件不少于 10个。 10 告警与报表 支持、邮件、syslog、snmp ftp等告警方式,支持冋时发送多人、 聚合发送、 单条发送、重发、发生统计等高级告警功能。 可以根据单个库、数据库组生成报表,包括支持严格按照塞班斯( SOX法案、等 级保护标准要求生成多维度综合报告。 支持按照数据库访问行为生成报表,智能识别帐号的增删、权限变更、密码修改、 特权操作等行为。 支持按照时间曲线统计流量、在线用户数、并发会话、 DDL操作数、DML操作数、 执行量取多的SQL语句等报表。 11 日志数据管 理 审计数据保留策略应至少满足天数和百分比两个控制参数,且支持 web界面可配 置,且恢复数据不影响正常的审计功能。 支持自动备份审计日志,备份完后通过 FTP方式外送到外部设备;备份文件需要 进行加密,且必须导入设备才能够进行恢复查看。 12 系统排错 系统内置故障排错系统,可以支持一键排错对服务异常、许可证异常、流量异常 等大部分常见故障的检测,并可提供快速的解决办法。 支持流量分析功能,包括抓包、包内容查看、自动探测 sql语句等。 13 资质要求 具备公安部颁发的《计算机息系统安全专用产品销售许可证》。 14 售后服务 原厂五年售后服务,包括安装调试、硬件质保、软件升级、特征库升级等。 数据库审计系统需求说明全文共2页,当前为第2页。 数据库审计系统需求说明全文共2页,当前为第2页。 数据库审计系统需求说明 在前端页面添加有关验证的标签: <input type="text" name="msg_code" id="msg_code" v-model="sms_code" @blur="check_sms_code"> <a href="javascript:;" @click="send_sms_code">[[sms_code... 验证用户名: 必须由字母, 数字下划线组成, 并且长度为 5 到 12 位 验证密码: 必须由字母, 数字下划线组成, 并且长度为 5 到 12 位 验证确认密码: 和密码相同 邮箱验证: xxxxx@xxx.com 验证码: 现在只需要验证用户已输入。 因为还没讲到服务器。 验证码生成 首先需要写html编程中的body主体部分,注入图片,输入文本框,以及注册按钮等。 body代码部分 这里选用的发送平台:榛子云平台:1.在"我的应用"->"详情"中打开:记住appId appSecret2. 下载开发包下载地址:http://smsow.zhenzikj.com/doc/sdk.html记住下载python3版本下面直接上代码#!/usr/bin/env python#coding=utf-8#导入包from captcha import zhenzismscli... Fdog系列(一):思来想去,不如写一个聊天软件,那就从仿QQ注册页面开始吧。 Fdog系列(二):html写完注册页面之后怎么办,用java写后台响应呀。 文章中出现的源码获取方式:评论区留下邮箱地址。 创作不易,各位看官点个关注,点个赞呗! 1. 前言 前面两篇分别使用html写了前端网页和使用java写后端响应代码,实现了前端与后端的数据交互,今天这篇将介绍如何将数据写入数据库,并且实