Flask博客開發——登陸驗證碼

這部分爲Flask博客的登陸頁面加個驗證碼。使用了PIL模塊生成驗證碼圖片,並經過Flask的session機制,進行驗證碼驗證。html

一、生成驗證碼前端

使用string模塊:string.ascii_letters+string.digits構造了驗證碼字符組合。使用的PIL模塊,構建了圖形對象,並進行劃線和高斯模糊處理。字體文件可單獨保存到工程裏。繪製字符串時,draw.text的前兩個參數爲字符的位置,能夠設置爲隨機數,使驗證碼各字符的位置不固定,而且相鄰字符略有重合。get_verify_code返回了圖形對象和字符串。git

import random
import string
from PIL import Image, ImageFont, ImageDraw, ImageFilter


def rndColor():
    '''隨機顏色'''
    return (random.randint(32, 127), random.randint(32, 127), random.randint(32, 127))

def gene_text():
    '''生成4位驗證碼'''
    return ''.join(random.sample(string.ascii_letters+string.digits, 4))

def draw_lines(draw, num, width, height):
    '''劃線'''
    for num in range(num):
        x1 = random.randint(0, width / 2)
        y1 = random.randint(0, height / 2)
        x2 = random.randint(0, width)
        y2 = random.randint(height / 2, height)
        draw.line(((x1, y1), (x2, y2)), fill='black', width=1)

def get_verify_code():
    '''生成驗證碼圖形'''
    code = gene_text()
    # 圖片大小120×50
    width, height = 120, 50
    # 新圖片對象
    im = Image.new('RGB',(width, height),'white')
    # 字體
    font = ImageFont.truetype('app/static/arial.ttf', 40)
    # draw對象
    draw = ImageDraw.Draw(im)
    # 繪製字符串
    for item in range(4):
        draw.text((5+random.randint(-3,3)+23*item, 5+random.randint(-3,3)),
                  text=code[item], fill=rndColor(),font=font )
    # 劃線
    draw_lines(draw, 2, width, height)
    # 高斯模糊
    im = im.filter(ImageFilter.GaussianBlur(radius=1.5))
    return im, code

 

二、表單類flask

爲LoginForm增長一個verify_code字段,用來輸入驗證碼。cookie

class LoginForm(FlaskForm):
    email = StringField('Email', validators=[DataRequired(), Length(1, 64),
                                             Email()],)
    password = PasswordField('Password', validators=[DataRequired()])
    verify_code = StringField('VerifyCode', validators=[DataRequired()])
    remember_me = BooleanField('Keep me logged in')
    submit = SubmitField('Log In')

 

三、視圖函數 session

使用io.BytesIO對象將驗證碼圖片轉化爲二進制形式,直接做爲響應返回前端。設置首部字段的內容格式,這樣二進制的內容就能以圖形形式在頁面中顯示。驗證碼字符串保存在flask.session對象中,對session的操做就像處理字典同樣。程序內部使用設置中的SECRET_KEY對session數據加密後,存儲在cookie中。app

from io import BytesIO
@auth.route('/code')
def get_code():
    image, code = get_verify_code()
    # 圖片以二進制形式寫入
    buf = BytesIO()
    image.save(buf, 'jpeg')
    buf_str = buf.getvalue()
    # 把buf_str做爲response返回前端,並設置首部字段
    response = make_response(buf_str)
    response.headers['Content-Type'] = 'image/gif'
    # 將驗證碼字符串儲存在session中
    session['image'] = code
    return response

 在登陸的視圖函數中,添加驗證碼驗證功能。注意通常驗證碼是不區分大小寫的,這裏將輸入的驗證碼和session中保存的驗證碼字符串都轉換成小寫後再做判斷。dom

@auth.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        if session.get('image').lower() != form.verify_code.data.lower():
            flash('Wrong verify code.')
            return render_template('auth/login.html', form=form)
        if user is not None and user.verify_password(form.password.data):
            login_user(user, form.remember_me.data)
            return redirect(request.args.get('next') or url_for('main.index'))
        flash('Invalid username or password.')
    return render_template('auth/login.html', form=form)

 

四、前端函數

在前端中加入了驗證碼圖形的路徑,該路徑指定爲生成圖形響應的視圖函數。當點擊驗證碼圖片時,驗證碼會予以更新。字體

{{ wtf.quick_form(form) }}
<img class="verify_code" src="/auth/code " onclick="this.src='/auth/code?'+ Math.random()">

 

調整下佈置,最終登陸表單會顯示成這個樣子:

下面是不一樣方式生成的驗證碼:

a. 無特效 b. 增長高斯模糊 c. 增長劃線
相關文章
相關標籤/搜索