BBS论坛(十三)

2019-02-13 16:04:59 浏览数 (1)

13.1点击更换图形验证码

(1)front/signup.html

代码语言:javascript复制
  <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

代码语言:javascript复制
.sign-box {
    width: 300px;
    margin: 0 auto;
    padding-top: 50px;
}

.captcha-addon {
    padding: 0;
    overflow: hidden;
}

.captcha-img {
    width: 94px;
    height: 32px;
    cursor: pointer;
}
代码语言:javascript复制
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

代码语言:javascript复制
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

代码语言:javascript复制
$(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

代码语言:javascript复制
     <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

代码语言:javascript复制
# 仙剑论坛-阿里大于短信验证码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 False

(2)exts.py

代码语言:javascript复制
alidayu = AlidayuAPI()

(3)config.py

代码语言:javascript复制
ALIDAYU_APP_KEY = 'LTxxxxxxBBfT8Q'
ALIDAYU_APP_SECRET = 'SRxxxxxx8IL8LhJ'
ALIDAYU_SIGN_NAME = '仙剑论坛网站'
ALIDAYU_TEMPLATE_CODE = 'SMS_136xxx947'

(4)perfect_bbs.py

代码语言:javascript复制
alidayu.init_app(app)

(5)common/views.py

代码语言:javascript复制
# 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

代码语言:javascript复制
    <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

代码语言:javascript复制
$(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

代码语言:javascript复制
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

代码语言:javascript复制
# 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='参数错误')

(3)front_signup.js

代码语言:javascript复制
$(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

代码语言:javascript复制
 <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

代码语言:javascript复制
# 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 resp

0 人点赞