13.1點擊更換圖形驗證碼 (1)front/signup.html (2)static/front/css/signup.css body { background: #f3f3f3; } .outer-box { width: 854px; background: #fff; margin: 0 ...
13.1點擊更換圖形驗證碼
(1)front/signup.html
<div class="form-group"> <div class="input-group"> <input type="text" class="form-control" name="graph_captcha" placeholder="圖形驗證碼"> <span class="input-group-addon captcha-addon"> <img id="captcha-img" class="captcha-img" src="{{ url_for('front.graph_captcha') }}" alt=""> </span> </div> </div>
(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; }View Code
(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; } };View Code
(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
<script src="{{ static('common/zlparam.js') }}"></script> <script src="{{ static('front/js/front_signup.js') }}"></script> <link rel="stylesheet" href="{{ static('front/css/front_signup.css') }}">
現在點擊驗證碼,就可以更換驗證碼了。
13.2.簡訊驗證碼
(1)utils/alidayu.py
# 仙劍論壇-阿裡大於簡訊驗證碼sdk import hashlib from time import time import logging import requests class 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 FalseView Code
(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,request from exts import alidayu from utils import restful from utils.captcha import Captcha bp = 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
<script src="{{ static('common/zlajax.js') }}"></script> <link rel="stylesheet" href="{{ static("common/sweetalert/sweetalert.css") }}"> <script src="{{ static("common/sweetalert/sweetalert.min.js") }}"></script> <script src="{{ static("common/sweetalert/zlalert.js") }}"></script> <script src="{{ static('common/zlparam.js') }}"></script> <script src="{{ static('front/js/front_signup.js') }}"></script> <link rel="stylesheet" href="{{ static('front/css/front_signup.css') }}">
(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 BaseForm from wtforms import StringField from wtforms.validators import regexp,InputRequired import hashlib class 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,request from exts import alidayu from utils import restful from utils.captcha import Captcha from .form import SMSCaptchaForm bp = 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='參數錯誤')View Code
(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']); } } }); }); });View Code
(4)front/signup.html
<meta name="csrf-token" content="{{ csrf_token() }}"> <script src="https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.min.js"></script>
13.4.驗證碼緩存
把front/views裡面的圖形驗證碼放到common/views.py下麵
common/views.py
# common/views.py __author__ = 'derek' from flask import Blueprint, request,make_response from exts import alidayu from utils import restful, zlcache from .form import SMSCaptchaForm from utils.captcha import Captcha from io import BytesIO bp = 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 respView Code