【Python百日进阶-WEB开发】Day179 - Django案例:11短信验证码

2024-02-13 22:30

本文主要是介绍【Python百日进阶-WEB开发】Day179 - Django案例:11短信验证码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 九、短信验证码
    • 9.1 短信验证码逻辑分析
    • 9.2 容联云通讯短信平台
      • 9.2.1 容联云通讯短信平台介绍
      • 9.2.2 容联云通讯短信SDK测试
        • 9.2.2.1 美多商城meiduo_mall.apps.verifications.libs中新建yuntongxun包,结构如下:
        • 9.2.2.2 ccp_sms.py代码
        • 9.2.2.3 CCPRestSDK.py ,python3代码
        • 9.2.2.4 测试发送短信
      • 9.2.3 封装发送短信单例类
    • 9.3 短信验证码接口设计和定义
    • 9.4 短信验证码后端逻辑
    • 9.5 短信验证码前端逻辑

九、短信验证码

9.1 短信验证码逻辑分析

在这里插入图片描述

9.2 容联云通讯短信平台

了解容联云通讯平台和短信SDK的使用方式,

9.2.1 容联云通讯短信平台介绍

  1. 容联云官网:https://www.yuntongxun.com/
    在这里插入图片描述
    2.注册登录
    在这里插入图片描述
  2. 通过认证,企业认证或个人认证,提交申请后一般需要第二天通过。发送短信0.06元/条,注册赠送8元,我发过一条了。
    在这里插入图片描述
  3. 添加容联云子应用,通过认证后可以上线应用
    在这里插入图片描述
  4. 添加测试号码
    在这里插入图片描述
  5. 短信模板
    在这里插入图片描述
  6. Python Demo中模板短信的使用说明
    https://doc.yuntongxun.com/p/5a533e0c3b8496dd00dce08c
    在这里插入图片描述
  7. 开发文档-SDK接口文件
    https://www.yuntongxun.com/doc/ready/demo/1_4_1_2.html
    在这里插入图片描述

9.2.2 容联云通讯短信SDK测试

9.2.2.1 美多商城meiduo_mall.apps.verifications.libs中新建yuntongxun包,结构如下:

在这里插入图片描述

9.2.2.2 ccp_sms.py代码
#-*- coding: UTF-8 -*-  from meiduo_mall.apps.verifications.libs.yuntongxun.CCPRestSDK import REST
# import ConfigParser
import ssl# 全局取消证书验证
ssl._create_default_https_context = ssl._create_unverified_context  #主帐号
accountSid= '8aaf07 这里填真实的主账号 5b0963df1';#主帐号Token
accountToken= 'b809 这里填真实的Token 4018733';#应用Id
appId='8a21 这里填真实的AppID 10d53ba6';#请求地址,格式如下,不需要写http://
serverIP='app.cloopen.com';#请求端口 
serverPort='8883';#REST版本号
softVersion='2013-12-26';# 发送模板短信# @param to 手机号码# @param datas 内容数据 格式为数组 例如:{'12','34'},如不需替换请填 ''# @param $tempId 模板Iddef sendTemplateSMS(to,datas,tempId):#初始化REST SDKrest = REST(serverIP,serverPort,softVersion)rest.setAccount(accountSid,accountToken)rest.setAppId(appId)result = rest.sendTemplateSMS(to,datas,tempId)print(result)#sendTemplateSMS(手机号码,内容数据,模板Id)
if __name__ == '__main__':# 注意测试的短信模板编号为1,短信验证码为123456,有效期为5分钟sendTemplateSMS('13953800865', ['123456', 5], 1)
9.2.2.3 CCPRestSDK.py ,python3代码

这个文件官网示例文件使用python2.7写的,有五六个地方需要修改,这是修改测试过的python3代码
修改内容主要包括:
1、头部导包
2、MD5加密
3、req.add_data
4、base64加密等

from hashlib import md5
import base64
import datetime
import urllib.request	# py3
import json
from meiduo_mall.apps.verifications.libs.yuntongxun.xmltojson import xmltojson	# py3
from xml.dom import minidom class REST:AccountSid=''AccountToken=''AppId=''SubAccountSid=''SubAccountToken=''ServerIP=''ServerPort=''SoftVersion=''Iflog=True #是否打印日志Batch=''  #时间戳BodyType = 'xml'#包体格式,可填值:json 、xml# 初始化# @param serverIP       必选参数    服务器地址# @param serverPort     必选参数    服务器端口# @param softVersion    必选参数    REST版本号def __init__(self,ServerIP,ServerPort,SoftVersion):self.ServerIP = ServerIP;self.ServerPort = ServerPort;self.SoftVersion = SoftVersion;# 设置主帐号# @param AccountSid  必选参数    主帐号# @param AccountToken  必选参数    主帐号Tokendef setAccount(self,AccountSid,AccountToken):self.AccountSid = AccountSid;self.AccountToken = AccountToken;   # 设置子帐号# # @param SubAccountSid  必选参数    子帐号# @param SubAccountToken  必选参数    子帐号Tokendef setSubAccount(self,SubAccountSid,SubAccountToken):self.SubAccountSid = SubAccountSid;self.SubAccountToken = SubAccountToken;    # 设置应用ID# # @param AppId  必选参数    应用IDdef setAppId(self,AppId):self.AppId = AppId; def log(self,url,body,data):print('这是请求的URL:')print (url);print('这是请求包体:')print (body);print('这是响应包体:')print (data);print('********************************')# 创建子账号# @param friendlyName   必选参数      子帐号名称def CreateSubAccount(self, friendlyName):self.accAuth()nowdate = datetime.datetime.now()self.Batch = nowdate.strftime("%Y%m%d%H%M%S")#生成sigsignature = self.AccountSid + self.AccountToken + self.Batch;signature = signature.encode('utf-8') # py3# sig = md5.new(signature).hexdigest().upper()sig = md5(signature).hexdigest().upper() # py3#拼接URLurl = "https://"+self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/SubAccounts?sig=" + sig#生成authsrc = self.AccountSid + ":" + self.Batch;# auth = base64.encodestring(src).strip()auth = base64.encodestring(src.encode()).strip() 	# py3req = urllib.request.Request(url)self.setHttpHeader(req)req.add_header("Authorization", auth)#xml格式body ='''<?xml version="1.0" encoding="utf-8"?><SubAccount><appId>%s</appId>\<friendlyName>%s</friendlyName>\</SubAccount>\'''%(self.AppId, friendlyName)if self.BodyType == 'json': #json格式body = '''{"friendlyName": "%s", "appId": "%s"}'''%(friendlyName,self.AppId)data=''# req.add_data(body)req.data = body.encode() # py3try:res = urllib.request.urlopen(req);data = res.read()res.close()if self.BodyType=='json':#json格式locations = json.loads(data)else:#xml格式xtj=xmltojson()locations=xtj.main(data)if self.Iflog:self.log(url,body,data)return locationsexcept Exception as error:if self.Iflog:self.log(url,body,data)return {'172001':'网络错误'}
9.2.2.4 测试发送短信

1.vscode终端输出
在这里插入图片描述

  1. 测试手机收到的短信
    在这里插入图片描述

9.2.3 封装发送短信单例类

问题:如果同时发送多个短信验证码,那么就会同时创建多个RET SDK的对象,会消耗很多额外的内存空间。
解决方法:使用单例类,它的特点是只有一个实例存在
使用场景:当我们希望在整个系统中,某个类只出现一个实例时,就可以使用单例类设计模式
改写后的代码:

#-*- coding: UTF-8 -*-  from meiduo_mall.apps.verifications.libs.yuntongxun.CCPRestSDK import REST
# import ConfigParser
import ssl# 全局取消证书验证
ssl._create_default_https_context = ssl._create_unverified_context  #主帐号
accountSid= '8aaf07087a331dc7017afb85b0963df1';
#主帐号Token
accountToken= 'b809c84015db41c8a4a3d84224018733';
#应用Id
appId='8a216da87a332d53017afb8d10d53ba6';
#请求地址,格式如下,不需要写http://
serverIP='app.cloopen.com';
#请求端口 
serverPort='8883';
#REST版本号
softVersion='2013-12-26';
# 发送模板短信
# @param to 手机号码
# @param datas 内容数据 格式为数组 例如:{'12','34'},如不需替换请填 ''
# @param $tempId 模板Id# def sendTemplateSMS(to,datas,tempId):
#     #初始化REST SDK
#     rest = REST(serverIP,serverPort,softVersion)
#     rest.setAccount(accountSid,accountToken)
#     rest.setAppId(appId)#     result = rest.sendTemplateSMS(to,datas,tempId)
#     print(result)class CCP(object):""" 发送短信验证码的单例类 """def __new__(cls, *args, **kwargs):""" 定义单例化的初始化方法,返回值为单例 """# 判断单例是否存在,利用动态赋值的_instance属性。如果单例不存在,就初始化单例if not hasattr(cls, '_instance'):cls._instance = super(CCP, cls).__new__(cls, *args, **kwargs)#初始化REST SDK,赋值给单例属性,实现与单例同生共死,唯一存在cls._instance.rest = REST(serverIP,serverPort,softVersion)cls._instance.rest.setAccount(accountSid,accountToken)cls._instance.rest.setAppId(appId)# 返回单例return cls._instance  def send_template_sms(self, to, datas, tempId):""" 定义对象方法,发送短信验证码 to:手机号码,字符串,多个手机号码用逗号分隔datas:发送内容,双元素列表,第一个元素为验证码字符串,第二个元素为整数有效时间(分钟)tempID:模板ID,测试模板为1返回值:成功:0,失败:-1"""result = self.rest.sendTemplateSMS(to,datas,tempId)print(result)# 根据发送是否成功返回0或-1if result.get('statusCode') == '000000':return 0else:return -1#sendTemplateSMS(手机号码,内容数据,模板Id)
if __name__ == '__main__':# 注意测试的短信模板编号为1,短信验证码为123456,有效期为5分钟# sendTemplateSMS('13953800865', ['123456', 5], 1)# 单例类发送短信验证码CCP().send_template_sms('13953800865', ['6543258', 5], 1)

9.3 短信验证码接口设计和定义

在这里插入图片描述

9.4 短信验证码后端逻辑

  1. verifications.urls.py中
from django.urls import path, re_path
from . import viewsapp_name = 'verifications'urlpatterns = [# 图形验证码,re_path路由正则校验,响应json数据,不需要重定向,也就不需要命名空间re_path(r'^image_codes/(?P<uuid>[\w-]+)/$', views.ImageCodeView.as_view()),# 短信验证码,re_path路由正则校验,响应json数据,不需要重定向,也就不需要命名空间re_path(r'^sms_codes/(?P<mobile>1[3-9]\d{9})/$', views.SMSCodeView.as_view()),]
  1. verifications.views.py中的短信验证码类视图
from django.views import View
from django_redis import get_redis_connection
from django import http
import random, loggingfrom meiduo_mall.apps.verifications.libs.captcha.captcha import captcha
from . import constants
from meiduo_mall.utils.response_code import RETCODE
from meiduo_mall.apps.verifications.libs.yuntongxun.ccp_sms import CCP# 创建日志输出器
logger = logging.getLogger('django')class SMSCodeView(View):""" 短信验证码 """def get (self, request, mobile):"""param:request,请求对象;mobile,手机号return:JSON"""""" 接收和校验参数 """# 接收参数image_code_client = request.GET.get('image_code')uuid = request.GET.get('uuid')# 校验参数,mobile不需要视图内校验,在路由处已经校验完毕了,错误进不了视图if not all([image_code_client, uuid]):return http.HttpResponseForbidden('缺少必传参数!')# 判断用户是否频繁发送短信验证码redis_conn = get_redis_connection('verify_code')     # 创建redis库的连接send_flag = redis_conn.get(f'send_flag_{mobile}')if send_flag:   #  已存在return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '发送短信验证码过于频繁!'})"""" 主体业务逻辑 """# 1.从redis库中提取图形验证码image_code_server = redis_conn.get(f'img_{uuid}')if image_code_server is None:return http.JsonResponse({'code': RETCODE.IMAGECODEERR, 'errmsg': '图形验证码已失效!'})# 2.删除redis中存储的图形验证码redis_conn.delete(f'img_{uuid}')# 3.对比图形验证码image_code_server = image_code_server.decode()   # 提取的数据时bytes类型,需要转换为字符串if image_code_client.lower() != image_code_server.lower():  # 全部转为小写return http.JsonResponse({'code': RETCODE.IMAGECODEERR, 'errmsg': '输入图形验证码有误!'})# 4.生成短信验证码:随机6位数字,不足前面补0, 000007sms_code = '%06d' % random.randint(0, 999999)logger.info(sms_code)   # 手动输出短信验证码的日志# 5.保存短信验证码,为优化redis的性能,使用管道队列操作# 5.1 创建redis pipeline管道队列pl = redis_conn.pipeline()# 5.2 将命令添加到队列中pl.setex(f'sms_{mobile}', constants.SMS_CODE_REDIS_EXPIRES, sms_code)   # sms_code存储到redis数据库pl.setex(f'send_flag_{mobile}', constants.SEND_SMS_CODE_INTERVAL, 1)    # 保存短信验证码标记,有效期60秒,标记1表示60秒内给该手机发送了验证码# 5.3 执行队列命令pl.excute()# 6.单例类发送短信验证码CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)""" 响应结果 """return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '短信验证码发送成功!'})

9.5 短信验证码前端逻辑

  1. register.html中的短信验证码部分
<li><label for="">短信验证码</label><input type="text" v-model="sms_code" @blur="check_sms_code" name="sms_code" id="sms_code" class="msg_input"><a @click="send_sms_code" class="get_msg_code">[[ sms_code_tip ]]</a><span class="error_tip" v-show="error_sms_code">[[ error_sms_code_message]]</span>
</li>
  1. register.js中的方法
//发送手机验证码
send_sms_code(){//避免恶意用户频繁点击获取短信验证码的A标签if (this.send_flag == true) {   //已经点击了发送短信验证码return;}this.send_flag = true;      //校验用户输入的mobile和image_codethis.check_mobile();this.check_image_code();if (this.error_image_code == true || this.error_mobile == true) {this.send_flag == false;return;}//?后面为查询字符串参数let url = '/sms_codes/'+ this.mobile +'/?image_code=' + this.image_code + '&uuid=' + this.uuid;  axios.get(url, {responseType: 'json'}).then(response => {if (response.data.code == '0') {    //发送短信验证码成功//展示倒计时60S效果 setInterval('回调函数', '时间间隔1000毫秒')let num = 60;let t = setInterval(() => {     // t 为定时器编号if (num == 1){          //倒计时即将结束clearInterval(t);   // 停止回调函数的执行this.sms_code_tip = '获取短信验证码';   // 还原 sms_code_tip 的提示信息this.generate_image_code();     //重新生成图形验证码this.send_flag == false;} else {                // 正在倒计时num -= 1;this.sms_code_tip = num + '秒';}}, 1000)} else {    if (response.data.code == '4001') { // 图形验证码错误// 渲染错误信息this.error_image_code_message = response.data.errmsg;this.error_image_code = true;this.send_flag == false;}}}).catch(error => {console.log(error.response);this.send_flag == false;})
},

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这篇关于【Python百日进阶-WEB开发】Day179 - Django案例:11短信验证码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/706777

相关文章

Python版本信息获取方法详解与实战

《Python版本信息获取方法详解与实战》在Python开发中,获取Python版本号是调试、兼容性检查和版本控制的重要基础操作,本文详细介绍了如何使用sys和platform模块获取Python的主... 目录1. python版本号获取基础2. 使用sys模块获取版本信息2.1 sys模块概述2.1.1

一文详解Python如何开发游戏

《一文详解Python如何开发游戏》Python是一种非常流行的编程语言,也可以用来开发游戏模组,:本文主要介绍Python如何开发游戏的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、python简介二、Python 开发 2D 游戏的优劣势优势缺点三、Python 开发 3D

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符

Python版本与package版本兼容性检查方法总结

《Python版本与package版本兼容性检查方法总结》:本文主要介绍Python版本与package版本兼容性检查方法的相关资料,文中提供四种检查方法,分别是pip查询、conda管理、PyP... 目录引言为什么会出现兼容性问题方法一:用 pip 官方命令查询可用版本方法二:conda 管理包环境方法

基于Python开发Windows自动更新控制工具

《基于Python开发Windows自动更新控制工具》在当今数字化时代,操作系统更新已成为计算机维护的重要组成部分,本文介绍一款基于Python和PyQt5的Windows自动更新控制工具,有需要的可... 目录设计原理与技术实现系统架构概述数学建模工具界面完整代码实现技术深度分析多层级控制理论服务层控制注

pycharm跑python项目易出错的问题总结

《pycharm跑python项目易出错的问题总结》:本文主要介绍pycharm跑python项目易出错问题的相关资料,当你在PyCharm中运行Python程序时遇到报错,可以按照以下步骤进行排... 1. 一定不要在pycharm终端里面创建环境安装别人的项目子模块等,有可能出现的问题就是你不报错都安装

Python打包成exe常用的四种方法小结

《Python打包成exe常用的四种方法小结》本文主要介绍了Python打包成exe常用的四种方法,包括PyInstaller、cx_Freeze、Py2exe、Nuitka,文中通过示例代码介绍的非... 目录一.PyInstaller11.安装:2. PyInstaller常用参数下面是pyinstal

Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题

《Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题》在爬虫工程里,“HTTPS”是绕不开的话题,HTTPS为传输加密提供保护,同时也给爬虫带来证书校验、... 目录一、核心问题与优先级检查(先问三件事)二、基础示例:requests 与证书处理三、高并发选型:

Python中isinstance()函数原理解释及详细用法示例

《Python中isinstance()函数原理解释及详细用法示例》isinstance()是Python内置的一个非常有用的函数,用于检查一个对象是否属于指定的类型或类型元组中的某一个类型,它是Py... 目录python中isinstance()函数原理解释及详细用法指南一、isinstance()函数