短信和图片验证码

任务: 短信验证码下发!
功能演示:
  短信和图片验证码
核心任务:
 前端功能
  功能1:点击按钮Ajax调用发送验证码功能
  功能2: 输完验证码后Ajax调用验证功能
 后端功能
  功能3: 发送验证码功能
  功能4:验证码检查
 后台核心逻辑(不需要手写)
  1. 发短信
  2. 生成短信验证码(随机生成6位数字)
 集成Redis
  1. 使用Redis代替session缓存,存储数据!
  2. Redis集成到Django中!
 扩展功能:
  统一接口返回结果的规范方法!
 
 
功能1: Django集成Redis
  因为我们短信验证码生命周期控制的非常严格!而且数据用完后不需要存储. 所以建议直接把数据存储在缓存/内存中!
  方案1: 使用session或cookie存储! session在当前浏览器有效! cookie 存储在用户本地不安全!
     session和cookie操作复杂,时间控制不精准!,存储的数据量非常有限!
  方案2: 使用Redis/Mongdb等key:value数据库!
     读写非常快, 存储数据量非常庞大, 有效期控制非常精准!
第1步: 下载django-redis模块  
  pip install django-redis
第2步: 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失效
第3步: views导入缓存cache模块
  from django.core.cache import cache
第4步: 使用
  def test_redis(request):
  # 存储数据
    cache.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(‘签名‘, ‘秘钥‘, ‘cn-
hangzhou‘)
#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‘, ‘模板名称‘)
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‘}))
功能5: 统一接口的数据格式:
统一的接口模块restful.py
#encoding: utf-8
from django.http import JsonResponse
class HttpCode(object):
  ok = 200
  paramserror = 400
  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,data=None):
    return result(code=HttpCode.ok,message=message,data=data)
 
  def params_error(message="",data=None):
    return result(code=HttpCode.paramserror,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两个
$(function(){
//短信验证码
//1. 找标签:btn1
//2. 定时器完成: 显示时间变化!!!
//setInterval(函数, 时间)
//3.难点: 定时器中函数,不断减1, 见到<0终止!!!!
var btn1 = $(‘#sendsms‘)
var count=5; // 倒计时数量 一般为60秒!
var timer =null; //定时器
//事件
btn1.click(function(){
phone = $(‘#phone‘).val()
if(phone==‘‘){
alert(‘请输入电话号码‘)
return false;
}
//ajax
$.ajax({
type: "get",
url: "/reader/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)
}
});
//end --发送ajax
//特效 start
//禁用
$(this).attr("disabled",‘true‘)
var _this= $(this);
//定时器实现时间每次减少1
timer = setInterval(function(){
count--;
console.log("剩余时间:"+count);
if(count>=0){
//this表示对象!!!! 表示定时器!!!!
//this.innerHTML="时间剩余"+ count+"秒";
_this.html(count+"秒s后重发")
}else{
_this.disabled = false;
clearInterval(timer);
_this.html("重新发送")
count=5
$(‘#sendsms‘).removeAttr("disabled")
}
},1000);
})
//特效 end
//短信验证
$("#smscode").change(function(){
//验证ajax
phone = $(‘#phone‘).val()
code = $(‘#smscode‘).val()
$.ajax({
type: "get",
url: "/reader/sms_check/",
data:"phone="+phone+"&code="+code,
success: function(msg){
console.log( "Data Saved: " + msg );
//已经为json
if(msg.code==‘200‘){
alert(‘成功‘);
}else{
$(‘#msg‘).html(‘手机验证码输入错误‘)
}
},
error:function(res){
//状态码
console.log(res.status)
}
});
//end验证ajax
})
//短信验证end
})
</script>
 
 
图文验证码
短信和图片验证码
图文验证码组件
官网 https://django-simple-captcha.readthedocs.io/en/latest/usage.html
参考网站:
https://my.oschina.net/hellotest/blog/1623597
https://blog.csdn.net/ros_donggua/article/details/81024634
第1步:安装图文验证成组件 
  pip install django-simple-captch
第2步:添加app
  # settings.py
  INSTALLED_APPS = [
  ...
  ‘captcha‘,
  ]
第3步:添加form表单类
forms.py
#一般将一些表单类写到同一个forms.py文件里
from captcha.fields import CaptchaField
from django import forms
class RegisterForm(forms.Form):
#为生成的验证码图片,以及输入框.
#captcha = CaptchaField(error_messages={‘invalid‘: ‘验证码输入有误‘})
captcha = CaptchaField()
第4步:页面初始化时生成验证码表单项
#跳转到首页时自动生成
def index(request):
  #生成验证码表单
  register_form = RegisterForm()
  return render(request, ‘index.html‘, {‘register_form‘: register_form})
第5步:前端使用
  <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
  验证码:{{ register_form.captcha }}
  </div>
此时网页渲染时会自动生成验证码表单
<img src="/captcha/image/2f3f82e5f7a054bf5caa93b9b0bb6cc308fb7011/" alt="captcha"
class="captcha" />
<input id="id_captcha_0" name="captcha_0" type="hidden"
value="2f3f82e5f7a054bf5caa93b9b0bb6cc308fb7011" />
<input autocomplete="off" id="id_captcha_1" name="captcha_1" type="text" />
第6步:验证和刷新
  
#验证码刷新
def img_refresh(request):
  if not request.is_ajax():
    return HttpResponse(‘不是Ajax请求‘)
  new_key = CaptchaStore.generate_key()
  to_json_response = {
  ‘hashkey‘: new_key,
  ‘image_url‘: captcha_image_url(new_key),
  }
  return HttpResponse(json.dumps(to_json_response))
#验证
def img_check(request):
  print(‘验证用户输入的图片验证码...‘)
  if request.is_ajax():
    cs = CaptchaStore.objects.filter(response=request.GET.get(‘code‘),
    hashkey=request.GET.get(‘hashkey‘))
    print(cs)
    if cs:
      json_data={‘status‘:1}
    else:
      json_data = {‘status‘:0}
      return JsonResponse(json_data)
  else:
    # raise Http404
    json_data = {‘status‘:0}
    return JsonResponse(json_data)
第7步:前端刷新和验证Ajax
  
<script>
$(function(){
//刷新
$(‘.captcha‘).click(function(){
$.getJSON("/duanxin/img_refresh/",function(result){
$(‘.captcha‘).attr(‘src‘, result[‘image_url‘]);
$(‘#id_captcha_0‘).val(result[‘hashkey‘])
});
return false;
})
//验证
$(‘#id_captcha_1‘).blur(function(){
console.log(‘用户输入的:‘+$(‘#id_captcha_1‘).val())
// 获取输入框和隐藏字段id_captcha_0的数值
code= $(‘#id_captcha_1‘).val();
hashkey=$(‘#id_captcha_0‘).val();
$.getJSON(‘/duanxin/img_check‘,
{‘code‘:code,‘hashkey‘:hashkey},function(res){
//1 验证码正确,0验证码错误
alert(‘验证判断结果...:‘+res)
if(res.status){
$("#msg").html(‘验证码正确‘)
}else{
$("#msg").html(‘验证码错误‘)
}
})
})
})
</script>
<!--短信Ajax-->
第8步:精细化setting配置
# django_simple_captcha 验证码配置其他配置项查看文档
# 默认格式
CAPTCHA_OUTPUT_FORMAT = ‘%(image)s %(text_field)s %(hidden_field)s ‘
CAPTCHA_NOISE_FUNCTIONS = (‘captcha.helpers.noise_null‘, # 没有样式
# ‘captcha.helpers.noise_arcs‘, # 线
# ‘captcha.helpers.noise_dots‘, # 点
)
# 图片中的文字为随机英文字母,如 mdsh
CAPTCHA_CHALLENGE_FUNCT = ‘captcha.helpers.random_char_challenge‘
# 图片中的文字为数字表达式,如2+2=
#CAPTCHA_CHALLENGE_FUNCT = ‘captcha.helpers.math_challenge‘
# 超时(minutes)
CAPTCHA_TIMEOUT = 1

相关推荐