13.1点击更换图形验证码
(1)front/signup.html
(2)static/front/css/signup.css
.sign-box { width: 300px; margin: 0 auto; padding-top: 50px;}.captcha-addon { padding: 0; overflow: hidden;}.captcha-img { width: 94px; height: 32px; cursor: pointer;}
body { background: #f3f3f3;}.outer-box { width: 854px; background: #fff; margin: 0 auto; overflow: hidden;}.logo-box { text-align: center; padding-top: 40px;}.logo-box img { width: 60px; height: 60px;}.page-title { text-align: center;}.sign-box { width: 300px; margin: 0 auto; padding-top: 50px;}.captcha-addon { padding: 0; overflow: hidden;}.captcha-img { width: 94px; height: 32px; cursor: pointer;}
(3)static/common/zlparam.js
var zlparam = { setParam: function (href,key,value) { // 重新加载整个页面 var isReplaced = false; var urlArray = href.split('?'); if(urlArray.length > 1){ var queryArray = urlArray[1].split('&'); for(var i=0; i < queryArray.length; i++){ var paramsArray = queryArray[i].split('='); if(paramsArray[0] == key){ paramsArray[1] = value; queryArray[i] = paramsArray.join('='); isReplaced = true; break; } } if(!isReplaced){ var params = {}; params[key] = value; if(urlArray.length > 1){ href = href + '&' + $.param(params); }else{ href = href + '?' + $.param(params); } }else{ var params = queryArray.join('&'); urlArray[1] = params; href = urlArray.join('?'); } }else{ var param = {}; param[key] = value; if(urlArray.length > 1){ href = href + '&' + $.param(param); }else{ href = href + '?' + $.param(param); } } return href; }};
(4)static/front/js/signup.js
$(function () { $('#captcha-img').click(function (event) { var self= $(this); var src = self.attr('src'); var newsrc = zlparam.setParam(src,'xx',Math.random()); self.attr('src',newsrc); });});
(5)front/signup.html中引用js和css
现在点击验证码,就可以更换验证码了。
13.2.短信验证码
(1)utils/alidayu.py
# 仙剑论坛-阿里大于短信验证码sdkimport hashlibfrom time import timeimport loggingimport requestsclass AlidayuAPI(object): APP_KEY_FIELD = 'ALIDAYU_APP_KEY' APP_SECRET_FIELD = 'ALIDAYU_APP_SECRET' SMS_SIGN_NAME_FIELD = 'ALIDAYU_SIGN_NAME' SMS_TEMPLATE_CODE_FIELD = 'ALIDAYU_TEMPLATE_CODE' def __init__(self, app=None): self.url = 'https://eco.taobao.com/router/rest' self.headers = { 'Content-type': 'application/x-www-form-urlencoded;charset=UTF-8', "Cache-Control": "no-cache", "Connection": "Keep-Alive", } if app: self.init_app(app) def init_app(self,app): config = app.config try: self.key = config[self.APP_KEY_FIELD] self.secret = config[self.APP_SECRET_FIELD] self.sign_name = config[self.SMS_SIGN_NAME_FIELD] self.api_params = { 'sms_free_sign_name': config[self.SMS_SIGN_NAME_FIELD], 'sms_template_code': config[self.SMS_TEMPLATE_CODE_FIELD], 'extend': '', 'sms_type': "normal", "method": "alibaba.aliqin.fc.sms.num.send", "app_key": self.key, "format": "json", "v": "2.0", "partner_id": "", "sign_method": "md5", } except Exception as e: logging.error(e.args) raise ValueError('请填写正确的阿里大鱼配置!') def send_sms(self,telephone,**params): self.api_params['timestamp'] = str(int(time() * 1000)) self.api_params['sms_param'] = str(params) self.api_params['rec_num'] = telephone newparams = "".join(["%s%s" % (k, v) for k, v in sorted(self.api_params.items())]) newparams = self.secret + newparams + self.secret sign = hashlib.md5(newparams.encode("utf-8")).hexdigest().upper() self.api_params['sign'] = sign resp = requests.post(self.url,params=self.api_params,headers=self.headers) data = resp.json() try: result = data['alibaba_aliqin_fc_sms_num_send_response']['result']['success'] return result except: print('='*10) print("阿里大于错误信息:",data) print('='*10) return False
(2)exts.py
alidayu = AlidayuAPI()
(3)config.py
ALIDAYU_APP_KEY = 'LTxxxxxxBBfT8Q'ALIDAYU_APP_SECRET = 'SRxxxxxx8IL8LhJ'ALIDAYU_SIGN_NAME = '仙剑论坛网站'ALIDAYU_TEMPLATE_CODE = 'SMS_136xxx947'
(4)perfect_bbs.py
alidayu.init_app(app)
(5)common/views.py
# common/views.py__author__ = 'derek'from flask import Blueprint,requestfrom exts import alidayufrom utils import restfulfrom utils.captcha import Captchabp = Blueprint("common",__name__,url_prefix='/c')@bp.route('/sms_captcha/')def sms_captcha(): telephone = request.args.get('telephone') if not telephone: return restful.params_error(message='请输入手机号码') #生成四位数的验证码 captcha = Captcha.gene_text(number=4) if alidayu.send_sms(telephone,code=captcha): return restful.success() else: # return restful.params_error(message='短信验证码发送失败!') return restful.success()
(6)signup.html
(7)front_signup.js
$(function () { $("#sms-captcha-btn").click(function (event) { event.preventDefault(); var self = $(this); //获取手机号码 var telephone = $("input[name='telephone']").val(); //使用js的正则判断手机号码,如果不合法,弹出提示框,直接return回去 if (!(/^1[3578]\d{9}$/.test(telephone))) { zlalert.alertInfoToast('请输入正确的手机号'); return; } zlajax.get({ 'url': '/c/sms_captcha?telephone='+telephone, 'success': function (data) { if(data['code'] == 200){ zlalert.alertSuccessToast('短信验证码发送成功'); self.attr("disabled",'disabled'); var timeCount = 60; var timer = setInterval(function () { timeCount--; self.text(timeCount); if(timeCount <= 0){ self.removeAttr('disabled'); clearInterval(timer); self.text('发送验证码'); } },1000); }else{ zlalert.alertInfoToast(data['message']); } } }); });});
13.3.短信验证码加密
(1)common/forms.py
from apps.forms import BaseFormfrom wtforms import StringFieldfrom wtforms.validators import regexp,InputRequiredimport hashlibclass SMSCaptchaForm(BaseForm): salt='dfurtn5hdsesjc*&^nd' telephone=StringField(validators=[regexp(r'1[3578]\d{9}')]) timestamp=StringField(validators=[regexp(r'\d{13}')]) sign=StringField(validators=[InputRequired()]) def validate(self): result=super(SMSCaptchaForm, self).validate() if not result: return False telephone=self.telephone.data timestamp=self.timestamp.data sign=self.sign.data sign2=hashlib.md5((timestamp+telephone+self.salt).encode('utf-8')).hexdigest() if sign==sign2: return True else: return False
(2)front/views.py
# common/views.py__author__ = 'derek'from flask import Blueprint,requestfrom exts import alidayufrom utils import restfulfrom utils.captcha import Captchafrom .form import SMSCaptchaFormbp = Blueprint("common",__name__,url_prefix='/c')# @bp.route('/sms_captcha/')# def sms_captcha():# telephone = request.args.get('telephone')# if not telephone:# return restful.params_error(message='请输入手机号码')# #生成四位数的验证码# captcha = Captcha.gene_text(number=4)# if alidayu.send_sms(telephone,code=captcha):# return restful.success()# else:# # return restful.params_error(message='短信验证码发送失败!')# return restful.success()@bp.route('/sms_captcha/',methods=['POST'])def sms_captcha():# telephone+timestamp+salt form=SMSCaptchaForm(request.form) if form.validate(): telephone=form.telephone.data captcha=Captcha.gene_text(number=4) if alidayu.send_sms(telephone,code=captcha): return restful.success() else: # return restful.paramas_error(message='参数错误') return restful.success() else: return restful.params_error(message='参数错误')
(3)front_signup.js
$(function () { $("#sms-captcha-btn").click(function (event) { event.preventDefault(); var self = $(this); //获取手机号码 var telephone = $("input[name='telephone']").val(); //使用js的正则判断手机号码,如果不合法,弹出提示框,直接return回去 if (!(/^1[3578]\d{9}$/.test(telephone))) { zlalert.alertInfoToast('请输入正确的手机号'); return; } var timestamp = (new Date).getTime(); var sign = md5(timestamp + telephone + 'dfurtn5hdsesjc*&^nd'); zlajax.post({ 'url': '/c/sms_captcha/', 'data': { 'telephone': telephone, 'timestamp': timestamp, 'sign': sign }, 'success': function (data) { if (data['code'] == 200) { zlalert.alertSuccessToast('短信验证码发送成功'); self.attr("disabled", 'disabled'); var timeCount = 60; var timer = setInterval(function () { timeCount--; self.text(timeCount); if (timeCount <= 0) { self.removeAttr('disabled'); clearInterval(timer); self.text('发送验证码'); } }, 1000); } else { zlalert.alertInfoToast(data['message']); } } }); });});
(4)front/signup.html
13.4.验证码缓存
把front/views里面的图形验证码放到common/views.py下面
common/views.py
# common/views.py__author__ = 'derek'from flask import Blueprint, request,make_responsefrom exts import alidayufrom utils import restful, zlcachefrom .form import SMSCaptchaFormfrom utils.captcha import Captchafrom io import BytesIObp = Blueprint("common", __name__, url_prefix='/c')# @bp.route('/sms_captcha/')# def sms_captcha():# telephone = request.args.get('telephone')# if not telephone:# return restful.params_error(message='请输入手机号码')# #生成四位数的验证码# captcha = Captcha.gene_text(number=4)# if alidayu.send_sms(telephone,code=captcha):# return restful.success()# else:# # return restful.params_error(message='短信验证码发送失败!')# return restful.success()@bp.route('/sms_captcha/', methods=['POST'])def sms_captcha(): # telephone+timestamp+salt form = SMSCaptchaForm(request.form) if form.validate(): telephone = form.telephone.data captcha = Captcha.gene_text(number=4) if alidayu.send_sms(telephone, code=captcha): zlcache.set(telephone, captcha) # 验证码保存到缓存中 return restful.success() else: # return restful.paramas_error(message='参数错误') zlcache.set(telephone, captcha) # 测试用 return restful.success() else: return restful.params_error(message='参数错误')@bp.route('/captcha/')def graph_captcha(): text,image = Captcha.gene_graph_captcha() zlcache.set(text.lower(),text.lower()) out = BytesIO() image.save(out,'png') #指定格式为png out.seek(0) #把指针指到开始位置 resp = make_response(out.read()) resp.content_type = 'image/png' return resp