功能演示
核心任务
前端功能:
点击按钮 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>
转载自:
来源: http://www.bubuko.com/infodetail-3356284.html