django-实现登录短信验证
功能演示
核心任务
- 前端功能:
- 点击按钮Ajax调用发送验证码功能
- 输完验证码后Ajax调用验证功能
- 后端功能:
- 功能1:发送验证码功能
- 功能2:验证码检查
- 后台核心逻辑(不需要手写)
- 功能3:发短信
- 功能4:生成短信验证码(随机生成6位数字)
- 集成Redis
- 使用Redis代替session缓存, 存储数据!
- Redis集成到Django中!
- 扩展功能:
- 统一接口返回结果的规范方法!
功能1:Django集成Redis
因为我们短信验证码生命周期控制的非常严格!而且数据用完后不需要存储. 所以建议直接把数据存储在缓存/内存中!
- 方案1: 使用session或cookie存储! session在当前浏览器有效! cookie 存储在用户本地不安全!session和cookie操作复杂,时间控制不精准!,存储的数据量非常有限!
- 方案2: 使用Redis/Mongdb等key:value数据库!读写非常快, 存储数据量非常庞大, 有效期控制非常精准!
第一步: 下载django-redis模块
pip install django-redis
第二步: 配置setting.py中写配置
配置Redis为Django的缓存,替换原来的session
#配置Redis为Django缓存 CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/0", #地址 "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", } } } # 将session缓存在Redis中 SESSION_ENGINE = "django.contrib.sessions.backends.cache" SESSION_CACHE_ALIAS = "default" # session 设置(可以不写) SESSION_COOKIE_AGE = 60 * 60 * 12 # 12小时 SESSION_SAVE_EVERY_REQUEST = True SESSION_EXPIRE_AT_BROWSER_CLOSE = True # 关闭浏览器,则COOKIE失效
第三步: views导入缓存cache模块
from django.core.cache import cache
第四步: 使用
def test_redis(request): # 存储数据 chache.set("name", "tom", 20) # 该值的有效期为20s # 判断Redis中是否存在 print(cache.has_kay("name")) # 包含: true # 获取 print(cache.get("name")) # 返回: tom 无返回null return HttpResponse("测试Redis")
功能2: 短信下发
第一步: 申请短信服务
参考文档 申请阿里云短信服务.pdf文档
第二步: 独立发送短信和生成验证码的模块
#!/usr/bin/env python #coding=utf-8 import random from aliyunsdkcore.client import AcsClient from aliyunsdkcore.request import CommonRequest from utils import restful def send_sms(phone,code): client = AcsClient('mxTYXZ4QDQecJQDN', 'znxNezmm4zfA9kPyqx1WrpznjCaJFT', 'cnhangzhou') #phone = '17600950805' #aa= '222222' code = "{'code':%s}"%(code) request = CommonRequest() request.set_accept_format('json') request.set_domain('dysmsapi.aliyuncs.com') request.set_method('POST') request.set_protocol_type('https') # https | http request.set_version('2017-05-25') request.set_action_name('SendSms') request.add_query_param('RegionId', 'cn-hangzhou') request.add_query_param('PhoneNumbers', phone) request.add_query_param('SignName', '北网') request.add_query_param('TemplateCode', 'SMS_162738723') request.add_query_param('TemplateParam',code ) response = client.do_action(request) # python2: print(response) print(str(response, encoding = 'utf-8')) return str(response, encoding = 'utf-8') #数字表示生成几位, True表示生成带有字母的 False不带字母的 def get_code(n=6,alpha=True): s = '' # 创建字符串变量,存储生成的验证码 for i in range(n): # 通过for循环控制验证码位数 num = random.randint(0,9) # 生成随机数字0-9 if alpha: # 需要字母验证码,不用传参,如果不需要字母的,关键字alpha=False upper_alpha = chr(random.randint(65,90)) lower_alpha = chr(random.randint(97,122)) num = random.choice([num,upper_alpha,lower_alpha]) s = s + str(num) return s if __name__ == '__main__': send_sms('18434288349', get_code(6,False)) print(get_code(6,False)) # 打印6位数字验证码 print(get_code(6,True)) # 打印6位数字字母混合验证码 print(get_code(4,False)) # 打印4位数字验证码 print(get_code(4,True)) # 打印4位数字字母混合验证码
功能3: 后台功能: 发送短信接口
流程:
获取手机号---->生成6位验证码–>缓存验证码到Redis—>发短信–>返回状态
# 发短信接口 def sms_send(request): # http://localhost:8000/duanxin/duanxin/sms_send/?phone=18434288349 # 1 获取手机号 phone = request.GET.get('phone') # 2 生成6位验证码 code = aliyunsms.get_code(6, False) # 3 缓存到Redis cache.set(phone,code,60) #60s有效期 print('判断缓存中是否有:',cache.has_key(phone)) print('获取Redis验证码:',cache.get(phone)) # 4 发短信 result = aliyunsms.send_sms(phone, code) return HttpResponse(result)
功能4: 短信验证码校验
流程:
获取前台电话和验证码----> 获取Redis中存的验证码—>对比是否相等–>返回结果
# 短信验证码校验 def sms_check(request): # /duanxin/sms_check/?phone=xxx&code=xxx # 1. 电话和手动输入的验证码 phone = request.GET.get('phone') code = request.GET.get('code') # 2. 获取redis中保存的code print('缓存中是否包含:',cache.has_key(phone)) print('取值:',cache.get(phone)) cache_code = cache.get(phone) # 3. 判断 if code == cache_code: return HttpResponse(json.dumps({'result':'OK'})) else: return HttpResponse(json.dumps({'result':'False'}))
手动在浏览器上给假设的参数进行测试:
http://localhost:8000/duanxin/sms_send/?phone=手机号
http://localhost:8000/duanxin/sms_check/?phone=手机号&code=验证码
功能5: 统一接口的数据格式:
独立restful.py 接口模块!
参考:
https://blog.csdn.net/xyy1028/article/details/84981627
https://www.runoob.com/w3cnote/restful-architecture.html
统一的接口模块restful.py
#encoding: utf-8 from django.http import JsonResponse class HttpCode(object): ok = 200 pageerror = 404 methoderror = 405 servererror = 500 # {"code":400,"message":"","data":{}} def result(code=HttpCode.ok,message="",data=None,kwargs=None): json_dict = {"code":code,"message":message,"result":data} if kwargs and isinstance(kwargs,dict) and kwargs.keys(): json_dict.update(kwargs) return JsonResponse(json_dict,json_dumps_params={'ensure_ascii': False}) def ok(message='OK',data=None): return result(code=HttpCode.ok,message=message,data=data) def page_error(message="",data=None): return result(code=HttpCode.pageerror,message=message,data=data) def method_error(message='',data=None): return result(code=HttpCode.methoderror,message=message,data=data) def server_error(message='',data=None): return result(code=HttpCode.servererror,message=message,data=data)
任何接口的返回结果,都是用resutful.py方法进行规整
# 短信验证码校验 def sms_check(request): # /duanxin/sms_check/?phone=xxx&code=xxx # 1. 电话和手动输入的验证码 phone = request.GET.get('phone') code = request.GET.get('code') # 2. 获取redis中保存的code print('缓存中是否包含:',cache.has_key(phone)) print('取值:',cache.get(phone)) cache_code = cache.get(phone) # 3. 判断 if code == cache_code: #格式统一调整后的 return restful.ok("OK",data=None) else: #格式统一调整后的 return restful.params_error("验证码错误", data=None)
功能6:前端短信Ajax两个
<script type="text/javascript"> //倒计时 var countdown=60; function sendemail(){ var obj = $("#btn"); settime(obj); } function settime(obj) { //发送验证码倒计时 if (countdown == 0) { obj.attr('disabled',false); //obj.removeattr("disabled"); obj.val("免费获取验证码"); countdown = 60; return; } else { obj.attr('disabled',true); obj.val("重新发送(" + countdown + ")"); countdown--; } setTimeout(function() { settime(obj) } ,1000) } </script> <script> //验证码 $('#btn').click(function () { phone = $('#phone').val(); if (phone == "") { alert("请输入手机号"); return false; } //ajax $.ajax({ type: "get", url: "/user/sms_send", data: "phone="+phone, success: function (msg) { console.log("Data Saved: "+msg); //转换为json obj = eval("("+msg+")"); console.log('结果: '+obj.Message); if (obj.Message == "OK") { $('#msg').html("短信发送成功") }else{ $('#msg').html("短信发送失败") } }, error: function (res) { //状态码 console.log(res.status) } }); }) </script> <script> //短信验证码校验 $('#smscode').change(function () { phone = $('#phone').val(); code = $('#smscode').val(); $.ajax({ type: "get", url: "/user/sms_check", data: "phone="+phone+"&code="+code, success: function (msg) { console.log("Data Saved: "+msg); if (msg.code == '200') { alert('成功'); }else{ $('#msg').html("手机验证码错误") } }, error: function (res) { console.log(res.status) } }); }) </script>
转载自:https://blog.csdn.net/Babysbreath_JTC/article/details/89319048
作者:子钦加油
出处:https://www.cnblogs.com/zmdComeOn/
个性签名:努力生活,努力走路
阿里云拼团:https://www.aliyun.com/1111/home?userCode=f4ee1llo1核2G1M,86一年,229三年;2核4G5M,799三年;2核8G5M,1399三年
腾讯云三月采购计划特价:https://cloud.tencent.com/act/cps/redirect?redirect=1073&cps_key=15d0b1673287c43fe946626d9f4e2eee&from=console1核2G1M,88一年;1核2G1M,268三年;2核4G5M,998一年;4核8G5M,2888元三年
出处:https://www.cnblogs.com/zmdComeOn/
个性签名:努力生活,努力走路
阿里云拼团:https://www.aliyun.com/1111/home?userCode=f4ee1llo1核2G1M,86一年,229三年;2核4G5M,799三年;2核8G5M,1399三年
腾讯云三月采购计划特价:https://cloud.tencent.com/act/cps/redirect?redirect=1073&cps_key=15d0b1673287c43fe946626d9f4e2eee&from=console1核2G1M,88一年;1核2G1M,268三年;2核4G5M,998一年;4核8G5M,2888元三年