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

news2025/1/13 4:20:34

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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决idea中无法拖动tab标签页的问题

1、按 Ctrl Alt S 打开设置&#xff0c;找到路径 File | Settings | Appearance & Behavior | Appearance 2、去掉勾选 Drag-and-drop with Alt pressed only 即可

单片机(MCU)-简单认识

简介&#xff1a; 内部集成了CPU&#xff0c;RAM&#xff0c;ROM&#xff0c;定时器&#xff0c;中断系统&#xff0c;通讯接口等一系列电脑的常用硬件功能。 单片机的任务是信息采集&#xff08;依靠传感器&#xff09;&#xff0c;处理&#xff08;依靠CPU&#xff09;&…

QT c++ 样式 设置 按钮(QPushButton)的渐变色美化

上一篇文章中描述了标签的渐变色美化,本文描述按钮的渐变色美化。 1.头文件 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> //#include "CustomButton.h"#include <QVBoxLayout> #include <QLinearGradient> #include <QPushButton&…

【物流管理系统 - IDEAJavaSwingMySQL】基于Java实现的物流管理系统导入IDEA教程

有问题请留言或私信 步骤 下载项目源码&#xff1a;项目源码 解压项目源码到本地 打开IDEA 左上角&#xff1a;文件 → 新建 → 来自现有源代码的项目 找到解压在本地的项目源代码文件&#xff0c;点击确定&#xff0c;根据图示步骤继续导入项目 查看项目目录&#xff…

【数据结构-堆】【二分】力扣3296. 移山所需的最少秒数

给你一个整数 mountainHeight 表示山的高度。 同时给你一个整数数组 workerTimes&#xff0c;表示工人们的工作时间&#xff08;单位&#xff1a;秒&#xff09;。 工人们需要 同时 进行工作以 降低 山的高度。对于工人 i : 山的高度降低 x&#xff0c;需要花费 workerTimes…

如何用SQL语句来查询表或索引的行存/列存存储方式|OceanBase 用户问题集锦

一、问题背景 自OceanBase 4.3.0版本起&#xff0c;支持了列存引擎&#xff0c;允许表和索引以行存、纯列存或行列冗余的形式创建&#xff0c;且这些存储方式可以自由组合。除了使用 show create table命令来查看表和索引的存储类型外&#xff0c;也有用户询问如何通过SQL语句…

CDA数据分析师一级经典错题知识点总结(3)

1、SEMMA 的基本思想是从样本数据开始&#xff0c;通过统计分析与可视化技术&#xff0c;发现并转换最有价值的预测变量&#xff0c;根据变量进行构建模型&#xff0c;并检验模型的可用性和准确性。【强调探索性】 2、CRISP-DM模型Cross Industry Standard Process of Data Mi…

算法题(32):三数之和

审题&#xff1a; 需要我们找到满足以下三个条件的所有三元组&#xff0c;并存在二维数组中返回 1.三个元素相加为0 2.三个元素的下标不可相同 3.三元组的元素不可相同 思路&#xff1a; 混乱的数据不利于进行操作&#xff0c;所以我们先进行排序 我们可以采取枚举的方法进行解…

【设计模式】介绍常见的设计模式

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 ✨ 介绍一下常见的设计模式✨ Spring 中常见的设计模式 这期内容主要是总结一下常见的设计模式&#xff0c;可…

单通道串口服务器(三格电子)

一、产品介绍 1.1 功能简介 SG-TCP232-110 是一款用来进行串口数据和网口数据转换的设备。解决普通 串口设备在 Internet 上的联网问题。 设备的串口部分提供一个 232 接口和一个 485 接口&#xff0c;两个接口内部连接&#xff0c;同 时只能使用一个口工作。 设 备 的网 口…

【蓝牙】win11 笔记本电脑连接 hc-06

文章目录 前言步骤 前言 使用电脑通过蓝牙添加串口 步骤 设置 -> 蓝牙和其他设备 点击 显示更多设备 更多蓝牙设置 COM 端口 -> 添加 有可能出现卡顿&#xff0c;等待一会 传出 -> 浏览 点击添加 hc-06&#xff0c;如果没有则点击 再次搜索 确定 添加成…

信息安全、网络安全和数据安全的区别和联系

信息安全、网络安全和数据安全是信息安全领域的三大支柱&#xff0c;它们之间既存在区别又相互联系。以下是对这三者的详细比较&#xff1a; 一.区别 1.信息安全 定义 信息安全是指为数据处理系统建立和采用的技术和管理的安全保护&#xff0c;保护计算机硬件、软件和数据不…

oracle闪回表

文章目录 闪回表案例1&#xff1a;&#xff08;未清理回收站时的闪回表--成功&#xff09;案例2&#xff08;清理回收站时的闪回表--失败&#xff09;案例3&#xff1a;彻底删除表&#xff08;不经过回收站--失败&#xff09;案例4&#xff1a;闪回表之后重新命名新表总结1、删…

如何让QPS提升20倍

一、什么是QPS QPS&#xff0c;全称Queries Per Second&#xff0c;即每秒查询率&#xff0c;是用于衡量信息检索系统&#xff08;例如搜索引擎或数据库&#xff09;或请求-响应系统&#xff08;如Web服务器&#xff09;每秒能够处理的请求数或查询次数的一个性能指标。以下是…

vue 实现打包并同时上传至服务器端

将 publish_script 及以下文件 upload.server.js 添加到 主文件下&#xff0c;与 src 同级别 具体操作步骤&#xff1a; 1、安装 npm install scp2 2、将下面两条命令加入至 package.json 的 scripts 中 "upload": "node publish_script/upload.server.js&q…

2015年IMO第3题

△ A B C \triangle ABC △ABC 的垂心为 H H H, A H AH AH 为直径的圆交 △ A B C \triangle ABC △ABC 的外接圆 ⨀ O \bigodot O ⨀O 于 A A A, Q Q Q. H Q HQ HQ 为为直径的圆交 ⨀ O \bigodot O ⨀O 于 Q Q Q, K K K. M M M 为 B C BC BC 边中点, F F F 为 A…

新活动平台建设历程与架构演进

01 前言 历时近两年的重新设计和迭代重构&#xff0c;用户技术中心的新活动平台建设bilibili活动中台终于落地完成&#xff01;并迎来了里程碑时刻 —— 接过新老迭代的历史交接棒&#xff0c;从内到外、从开发到搭建实现全面升级&#xff0c;开启了活动生产工业化新时代&#…

《安富莱嵌入式周报》第348期:开源低功耗测试仪,开源创意万用表,续航100-300小时,开源PCB电机,自制shell和网络协议栈,开源水培自动化系统

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版&#xff1a; https://www.bilibili.com/video/BV1Tzr9Y3EQ7/ 《安富莱嵌入式周报》第348期&#xff1a;开源低功…

【Kaggle】练习赛《预测贴纸的销量》(下)

前言 上篇利用各地区的GDP数据还填充目标标签的缺失值&#xff1b;中篇顺着这个思路&#xff0c;利用这个原理来预测未来的销量&#xff0c;具体方法思路&#xff1a;先一一对国家、产品和商店进行汇总&#xff0c;然后对未来三年的每日销售额进行预测&#xff0c;然后再进行分…

RT-DETR代码详解(官方pytorch版)——参数配置(1)

前言 RT-DETR虽然是DETR系列&#xff0c;但是它的代码结构和之前的DETR系列代码不一样。 它是通过很多的yaml文件进行参数配置&#xff0c;和之前在train.py的parser argparse.ArgumentParser()去配置所有参数不同&#xff0c;所以刚开始不熟悉代码的时候可能不知道在哪儿修…