图片和短信验证码(头条项目-06)

1 图形验证码接口设计

将后端⽣成的图⽚验证码存储在redis数据库2号库

结构:

  • {'img_uuid':'0594'}

1.1 创建验证码⼦应⽤

$ cd apps
$ python ../../manage.py startapp verifications
# 注册新应⽤
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'userapp',
    'newsapp',
    'verifications',
]

1.2 图形验证码接⼝设计

1.2.1 请求⽅式
选项⽅案
请求⽅法GET
请求地址 1/imgcodes/(?P[\w-]+)/
1.2.2 请求参数:路径参数
参数名类型是否必传说明
uuidstring唯⼀编号
1.2.3 响应结果 图⽚验证码格式:image/png

1.3 图形验证码接⼝定义

1.3.1 图形验证码视图
# views.py视图⽂件
class ImageCode(View):
    def get(self, request, uuid):
        pass
1.3.2 配置路由
# 项⽬根路由
re_path('^', include(('verifications.urls', 'verifications',),
                     namespace='verify')),
# ⼦路由
re_path('^image_code/(?P<uuid>[\w-]+)/$', views.ImageCode.as_view())

2 图片验证码后端逻辑

2.1 配置Redis数据库

# 配置redis数据库专⻔存储验证码
"verify_code": {  # 验证码
    "BACKEND": "django_redis.cache.RedisCache",
    "LOCATION": "redis://192.168.1.6:6379/2",
    "OPTIONS": {
        "CLIENT_CLASS": "django_redis.client.DefaultClient",
    }
}

2.2 安装模块

pip install pillow
pip install captcha

2.3 图⽚验证码视图

# constants.py⽂件内容
# 图⽚验证码有效期,单位:秒
IMAGE_CODE_REDIS_EXPIRES = 300

# views.py视图⽂件
from captcha.image import ImageCaptcha
from django_redis import get_redis_connection
from newsdemo.apps.verifications import constants

class ImageCode(View):
    def get(self, request, uuid):
        # 随机⽣成四位数字
        seeds = string.digits
        random_str = random.choices(seeds, k=4)
        imgcode = "".join(random_str)
        # ⽣成图⽚验证码
        img = ImageCaptcha().generate(chars=imgcode)
        # 保存图⽚验证码到redis
        redis_conn = get_redis_connection('verify_code')

        redis_conn.setex('img_%s' % uuid, 
                         constants.IMAGE_CODE_REDIS_EXPIRES, imgcode)
        return http.HttpResponse(img, content_type='image/png')

3 图片验证码前端逻辑

3.1 Vue实现图形验证码展示

3.1.1 register.js
mounted(){
    // ⽣成图形验证码
    this.generate_img_code();
    },
methods:{
    generate_img_code:function () {
        // ⽣成UUID generateUUID() : 封装在common.js⽂件中,需要提前引⼊
        this.uuid = generateUUID();
        // 拼接图形验证码请求地址
        this.img_url = "/imgcodes/" + this.uuid + "/";
    },
...
}
3.1.2 register.html
<p class="form-row form-row-wide">
    <input style="width: 250px;" placeholder="图⽚验证码"
           type="text" class="input-text">
    <img style="height: 40px;float: right;" :src="img_url"
         @click="generate_img_code">
    <span class="error-tip">图⽚验证码有误</span>
</p>
3.1.3 图形验证码展示和存储效果

3.2 Vue实现图形验证码校验

3.2.1 register.html
<p class="form-row form-row-wide">
    <input style="width: 250px;" placeholder="图⽚验证码" v-model='imgcode' 
           @blur="check_imgcode" name="imgcode"
           type="text" class="input-text">
    <img style="height: 40px;float: right;" :src="img_url"
         @click="generate_img_code">
    <span class="error-tip" v-show="error_imgcode">${error_imgcode_msg}</span>
</p>
3.2.2 register.js
// 校验图⽚验证码
check_imgcode:function () {
    if (!this.imgcode) {
        this.error_imgcode_msg = '请填写图⽚验证码';
        this.error_imgcode = true;
    } else {
        this.error_imgcode = false;
    }
}
3.2.3 校验效果

4 短信验证码接口设计

4.1 短信验证码接⼝设计

4.1.1 请求⽅式
选项⽅案
请求⽅法GET
请求地址 1/sms_codes/(?P1[35789]\d{9})/
4.1.2 请求参数:路径参数和查询字符串
参数名类型是否必传说明
phonestring⼿机号
imgcodestring图⽚验证码
uuidstring唯⼀编号
4.1.3 响应结果:JSON
响应结果响应内容
code状态码
errmsg错误信息

4.2 短信验证码接⼝定义

class SMSCode(View):
    """短信验证码"""

    def get(self, reqeust, phone):
        """
        :param reqeust: 请求对象
        :param phone: ⼿机号
        :return: JSON
        """
        pass

4.3 知识要点

  1. 保存短信验证码是为注册做准备的。
  2. 为了避免⽤户使⽤图形验证码恶意测试后端提取了图形验证码后,⽴即删除图形验证码
  3. Django不具备发送短信的功能,所以我们借助 第三⽅的互亿⽆线短信平台 来帮助我们发送短信验证码。

5 互亿无线短信平台

5.1 平台介绍

互亿⽆线官⽹ https://www.ihuyi.com/

⽬前注册可免费使⽤50条短信验证码

5.2 平台管理中⼼

5.3 接⼊⽂档

跳转地址:短信验证码接入指南_短信平台帮助_互亿无线 (ihuyi.com)

5.4 配置参数

在dev.py配置⽂件中添加参数

# 互亿⽆线短信验证码参数
# APIID
APIID = "C74**64"
# APIKEY
APIKEY = "62de***8932d50c2"

5.5 下载Python3.8⽀持的SDK

# utils/huyi_sms/sms3.py
# !/usr/local/bin/python
# -*- coding:utf-8 -*-
from urllib.request import urlopen
from urllib.parse import urlencode
from django.conf import settings
import json


def send_sms_code(smscode, phone):
    # APIID(⽤户中⼼【验证码通知短信】-【产品纵览】查看)
    account = settings.APIID
    # APIKEY(⽤户中⼼【验证码通知短信】-【产品纵览】查看)
    password = settings.APIKEY
    text = "您的验证码是:%s。请不要把验证码泄露给其他⼈。" % smscode
    data = {'account': account, 'password': password, 'content': text,
            'mobile': phone, 'format': 'json'}
    req = urlopen(url='https://106.ihuyi.com/webservice/sms.php?'
                      'method=Submit',
                  data=urlencode(data).encode())
    content = req.read().decode()
    print(content)
    # code等于2代表提交成功,否则提交失败
    # smsid等于0代表提交失败,否则显示⻓度20流⽔号
    # b'{"code":2,"msg":"\xe6\x8f\x90\xe4\xba\xa4\xe6\x88\x90\xe5\x8a\x9f",
    # "smsid":"16063783563405105174"}'
    return json.loads(content)

6 短信验证码后端逻辑

6.1 短信验证码后端逻辑实现

class SMScodeView(View):
    def get(self, request, phone):
        """
        匹配并删除图形验证码
        发送短信验证码
        :param request:
        :param phone:
        :return:
        """
        # 1. 获取请求参数(路径参数+查询参数)
        imgcode_client = request.GET.get('imgcode', '')
        uuid = request.GET.get('uuid', '')

        # 2. 校验参数
        if not all([phone, imgcode_client, uuid]):
            return JsonResponse({'code': '4001', 
                                 'errormsg': '缺少必须传递的参数'})

        # 3. 校验图⽚验证码(⽤户输⼊验证码和⽣成验证码)
        redis_conn = django_redis.get_redis_connection('verify_code')
        imgcode_server = redis_conn.get('img_%s' % uuid)
        print(uuid)
        print(imgcode_server)

        # 3.1 图⽚验证码是否过期
        if imgcode_server is None:
            return JsonResponse({'code': '4002', 
                                 'errormsg': '图⽚验证码已经过期'})

        # 3.2 匹配图⽚验证码
        if imgcode_client.lower() != imgcode_server.decode('utf-8').lower():
            return JsonResponse({'code': '4003', 
                                 'errormsg': '图⽚验证码不匹配'})
        try:
            # 删除redis中的图⽚验证码
            redis_conn.delete('img_%s' % uuid)
        except Exception as e:
            logger.error(e)

        # 4. ⽣成短信验证码(6位)
        seed = string.digits
        r = random.choices(seed, k=6)
        smscode_str = "".join(r)

        # 5. 保存短信验证码(redis数据库2号库存储)
        redis_conn.setex('sms_%s' % uuid, 60, smscode_str)

        # 6. 发送短信验证码
        ret = send_sms_code(smscode_str, phone)
        if ret.code == 2:
            return JsonResponse({'code': 200, 'errormsg': 'OK'})

        # 7. 返回响应结果
        return JsonResponse({'code': 5001, 'errormsg': '发送短信验证码错误'})

7 短信验证码前端逻辑

7.1 Vue绑定短信验证码

7.1.1 register.html
<p class="form-row form-row-wide">
    <input style="width: 250px;" placeholder="短信验证码" v-model='smscode'
           @blur="check_smscode" name="msgcode"
           type="text" class="input-text" id="reg_mescode">
    <span class="error-tip" v-show="error_code">${error_msgcode_msg}</span>
    <a href="javascript:;" style="position: relative;left:150px;"
       @click="send_code()">${smscode_btn} </a>
</p>
7.1.2 register.js
check_smscode:function () {
    //获取验证码⻓度
    let reg = /^\d{6}$/;
    
    //校验规则
    if (!reg.test(this.smscode)) {
        this.error_smscode_msg = '请填写短信验证码';
        this.error_smscode = true;
    } else {
        this.error_smscode = false;
    }
}

7.2 axios请求短信验证码

7.2.1 发送短信验证码事件处理
send_smscode:function () {
    //发送短信验证码
    //1.判断短信验证码是否正在发送
    if (this.send_flag) {
        return;
    }
    //2.修改发送状态
    this.send_flag = true;
    //3.校验⽤户输⼊的⼿机号和图⽚验证码
    this.check_phone();
    this.check_imgcode();
    if (this.error_phone || this.error_imgcode) {
        this.send_flag = false;
        return;
    }
    //4.发送短信验证码
    var url = '/smscodes/' + this.phone + '/?imgcode=' +
        this.imgcode + '&uuid=' + this.uuid;
    axios.get(url, {
        responseType: 'json'
    }).then(response => {
        console.log(response.data.code);
        console.log(typeof (response.data.code));
        if (response.data.code == '200') {
            let num = 60;
            var i = setInterval(() => {
                if (num == 1) {
                    clearInterval(i);
                    this.smscode_btn = '获取短信验证码';
                    this.send_flag = false;
                } else {
                    num -= 1;
                    this.smscode_btn = '倒计时:' + num + '秒';
                }
            }, 1000, 60)
        } else {
            if (response.data.data == '4001' || response.data.data == '4002'
                || response.data.data == '4003' || 
                response.data.data == '5001') {
                this.error_smscode_msg =
                    response.data.errormsg;
                this.error_smscode = true;
            }

            //重新⽣成图⽚验证码
            this.generate_imgcode();
            //重置发送状态
            this.send_flag = false;
        }
    }).catch(error => {
        console.log(error.response);
    });
}

8 用户注册时短信验证码校验功能

8.1 注册时短信验证前端逻辑

8.1.1 register.html
<p class="form-row form-row-wide">
    <input style="width: 230px;" v-model="smscode" placeholder="短信验证码"
           @blur="check_smscode" name="msgcode"
           type="text" class="input-text" id="reg_mescode">
    <span class="error-tip" v-show="error_smscode">${error_smscode_msg}</span>

    <a href="javascript:;" style="font-size: 16px;text-align: center;
    font-weight: normal;float: right" id="reg_mescode_btn"
       able="able" @click="send_smscode">${smscode_btn}</a>
</p>
 8.1.2 register.js
check_smscode:function () {
    // 1.短信验证码格式校验
    let reg = /^\d{6}$/;
    if (!reg.test(this.smscode)) {
        this.error_smscode = true;
    } else {
        this.error_smscode = false;
    }
    // 2.⼀致性校验
    if (!this.error_smscode) {
        axios.get('/check_smscode/' + this.phone + '/?smscode=' 
            + this.smscode, {
            responseType: 'json'
        }).then(response => {
            let code = response.data.code;
            if (code == '4001' || code == '4002' || code ==
                if (code == '4001' || code == '4002' || code == '4003') {
                    this.error_smscode = true;
                    this.error_smscode_msg =
                        response.data.errormsg;
                } else {
                    this.error_smscode = false;
                }
        })
    }
}

8.2 注册时短信验证后端逻辑

# verifications/views.py
class CheckSMScode(View):
    def get(self, request, phone):
        """
        ⽤户注册时短信验证码校验
        :param request:
        :param phone:
        :return:
        """
        # 接收请求参数
        smscode_client = request.GET.get('smscode', '')
        # 校验参数
        if not all([phone, smscode_client]):
            return JsonResponse({'code': '4001', 'errormsg': '缺少必传参数'})
        # 查询服务器端短信验证码
        redis_conn = django_redis.get_redis_connection('verify_code')
        smscode_server = redis_conn.get('sms_%s' % phone)
        # 匹配(⾮空判断/有效性判断)
        if smscode_server is None:
            return JsonResponse({'code': '4002', 'errormsg': '短信验证码失效'})
        smscode_server = smscode_server.decode('utf-8')
        if smscode_client != smscode_server:
            return JsonResponse({'code': '4003', 
                                 'errormsg': '短信验证码不⼀致'})
        # 响应结果
        return JsonResponse({'code': '200', 'errormsg': 'OK'})

9 避免频繁发送短信验证码

存在的问题:

  • 虽然我们在前端界⾯做了60秒倒计时功能。
  • 但是恶意⽤户可以 绕过前端界⾯向后端频繁请求短信验证码

解决办法:

  • 在 后端也要限制 ⽤户请求短信验证码的频率。60秒内只允许⼀次请求短信 验证码
  • 在Redis数据库中缓存⼀个数值,有效期设置为60秒

9.1 避免频繁发送短信验证码逻辑实现

9.1.1 提取并校验 is_send
is_send = redis_conn.get('is_send_%s' % phone)
if is_send:
    return JsonResponse({'code': 4001, 'error_msg': '发送短信过于频繁'})
9.1.2 is_send 、smscode 存⼊redis数据库
# 保存短信验证码
redis_conn.setex('sms_%s' % phone, 60, smscode)
# 保存is_send
redis_conn.setex('is_send_%s' % phone, 60, 1)
9.1.3 界⾯渲染 频繁发送短信提示信息
if (response.data.code == '4001') {
    this.error_smscode_msg = response.data.error_msg;
    this.error_smscode_code = true;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/954637.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java8 springboot 集成javaFx 实现一个客户端程序

1. 先创建一个springboot 程序(此步骤不做流程展示) 2. 更改springboot的版本依赖和导入所需依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.7</versio…

linux手动安装mysql5.7

一、下载mysql5.7 1、可以去官方网站下载mysql-5.7.24-linux-glibc2.12-x86_64.tar压缩包&#xff1a; https://downloads.mysql.com/archives/community/ 2、在线下载&#xff0c;使用wget命令&#xff0c;直接从官网下载到linux服务器上 wget https://downloads.mysql.co…

数据结构(链表 哈希表)

在Python中&#xff0c;链表和哈希表都是常见的数据结构&#xff0c;可以用来存储和处理数据。 链表是一种线性数据结构&#xff0c;由一系列节点组成&#xff0c;每个节点包含一个数据元素和一个指向下一个节点的指针。链表可以用来实现栈、队列以及其他数据结构。Python中可…

【GPT进化之路】从 GPT-1 的初试锋芒到 GPT-4 的跨模态智能时代

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…

linux之进程信号(初识信号,信号的产生)

目录 引入一、初识信号(信号预备知识)1.生活中的信号2.Linux中的信号3.信号进程得出的初步结论 二、信号的产生1.通过终端输入产生信号拓展: 硬件中断2.调用系统函数向进程发信号3.硬件异常产生信号4.软件条件产生信号拓展: 核心转储技术总结一下&#xff1a; 引入 一、初识信…

24-25-1-单片机开卷部分习题和评分标准

依据相关规定试卷必须按评分标准进行批改。 给分一定是宽松的&#xff0c;能给分一定给&#xff0c;如有疑问也可以向学院教务办申请查卷。 一部分学生期末成绩由于紧张或其他原因导致分数过低&#xff0c;也是非常非常遗憾的。 个人也是非常抱歉的。 开卷考试 简答题 第一…

电动汽车V2G技术Matlab/Simulink仿真模型

今天给大家更新关于V2G技术的仿真&#xff0c;不是研究这个方向的&#xff0c;可能会对这个名称比较陌生&#xff0c;那么&#xff0c;什么是“V2G”&#xff1f; V2G全称&#xff1a;Vehicle-to-Grid&#xff0c;即车网互动&#xff0c;利用电动汽车特有的储能功能与电网“双…

统计学习算法——决策树

内容来自B站Up主&#xff1a;风中摇曳的小萝卜https://www.bilibili.com/video/BV1ar4y137GD&#xff0c;仅为个人学习所用。 问题引入 有15位客户向某银行申请贷款&#xff0c;下面是他们的一些基本信息&#xff0c;类别列表示是否通过贷款申请&#xff0c;是表示通过贷款申…

Pytorch导出onnx模型并在C++环境中调用(含python和C++工程)

Pytorch导出onnx模型并在C环境中调用&#xff08;含python和C工程&#xff09; 工程下载链接&#xff1a;Pytorch导出onnx模型并在C环境中调用&#xff08;python和C工程&#xff09; 机器学习多层感知机MLP的Pytorch实现-以表格数据为例-含数据集和PyCharm工程中简单介绍了在…

Uniapp判断设备是安卓还是 iOS,并调用不同的方法

在 UniApp 中&#xff0c;可以通过 uni.getSystemInfoSync() 方法来获取设备信息&#xff0c;然后根据系统类型判断当前设备是安卓还是 iOS&#xff0c;并调用不同的方法。 示例代码 export default {onLoad() {this.checkPlatform();},methods: {checkPlatform() {// 获取系…

VMWare虚拟机+Ubuntu24.04+ROS2Jazzy版本安装——踩坑及爬坑过程

VMWare安装 VMWare安装参考VMWare安装&#xff0c;WMWare workstation从17版本以后就面向个人用户免费开放了&#xff0c;所以在安装的最后只要勾选“用于个人”这个选项&#xff0c;就无需再输入激活码等&#xff0c;非常方便。 WMWare workstation17的获取地址&#xff1a;通…

【Golang 面试题】每日 3 题(三十一)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/UWz06 &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏…

分布式数据存储基础与HDFS操作实践(副本)

以下为作者本人撰写的报告&#xff0c;步骤略有繁琐&#xff0c;不建议作为参考内容&#xff0c;可以适当浏览&#xff0c;进一步理解。 一、实验目的 1、理解分布式文件系统的基本概念和工作原理。 2、掌握Hadoop分布式文件系统&#xff08;HDFS&#xff09;的基本操作。 …

《OpenCV》——模版匹配

文章目录 OpenCV——模版匹配简介模版匹配使用场景OpenCV 中模板匹配的函数参数 OpenCV——模版匹配实例导入所需库读取图片并处理图片对模版图片进行处理进行模版匹配显示模版匹配的结果注意事项 OpenCV——模版匹配简介 OpenCV 是一个非常强大的计算机视觉库&#xff0c;其中…

迅翼SwiftWing | ROS 固定翼开源仿真平台正式发布!

经过前期内测调试&#xff0c;ROS固定翼开源仿真平台今日正式上线&#xff01;现平台除适配PX4ROS环境外&#xff0c;也已实现APROS环境下的单机飞行控制仿真适配。欢迎大家通过文末链接查看项目地址以及具体使用手册。 1 平台简介 ROS固定翼仿真平台旨在实现固定翼无人机决策…

基于深度学习的视觉检测小项目(十二) 使用线条边框和渐变颜色美化界面

到目前为止&#xff0c;已经建立起了基本的项目架构&#xff0c;样式表体系也初步具备&#xff0c;但是与成品的界面相比&#xff0c;还是差点什么。 我的界面效果图&#xff1a; 优秀demo的界面截图&#xff1a; 是的&#xff0c;我的界面太“平” 了&#xff0c;没有立体感&…

MySQL(高级特性篇) 06 章——索引的数据结构

一、为什么使用索引 索引是存储引擎用于快速找到数据记录的一种数据结构&#xff0c;就好比一本教科书的目录部分&#xff0c;通过目录找到对应文章的页码&#xff0c;便可快速定位到需要的文章。MySQL中也是一样的道理&#xff0c;进行数据查找时&#xff0c;首先查看查询条件…

Springboot + vue 图书管理系统

&#x1f942;(❁◡❁)您的点赞&#x1f44d;➕评论&#x1f4dd;➕收藏⭐是作者创作的最大动力&#x1f91e; &#x1f496;&#x1f4d5;&#x1f389;&#x1f525; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;欢迎留言讨论 &#x1f525;&#x1f525;&…

2025年01月15日Github流行趋势

1. 项目名称&#xff1a;tabby - 项目地址url&#xff1a;https://github.com/TabbyML/tabby - 项目语言&#xff1a;Rust - 历史star数&#xff1a;25764 - 今日star数&#xff1a;1032 - 项目维护者&#xff1a;wsxiaoys, apps/autofix-ci, icycodes, liangfung, boxbeam - 项…

详解数据增强中的平移shft操作

Shift 平移是指在数据增强&#xff08;data augmentation&#xff09;过程中&#xff0c;通过对输入图像或目标进行位置偏移&#xff08;平移&#xff09;&#xff0c;让目标在图像中呈现出不同的位置。Shift 平移的目的是增加训练数据的多样性&#xff0c;从而提高模型对目标在…