Flask博客开发——登录验证码

Posted ik-heu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flask博客开发——登录验证码相关的知识,希望对你有一定的参考价值。

这部分为Flask博客的登录页面加个验证码。使用了PIL模块生成验证码图片,并通过Flask的session机制,进行验证码验证。

1、生成验证码

使用string模块:string.ascii_letters+string.digits构造了验证码字符组合。使用的PIL模块,构建了图形对象,并进行划线和高斯模糊处理。字体文件可单独保存到工程里。绘制字符串时,draw.text的前两个参数为字符的位置,可以设置为随机数,使验证码各字符的位置不固定,并且相邻字符略有重合。get_verify_code返回了图形对象和字符串。

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

 

2、表单类

为LoginForm增加一个verify_code字段,用来输入验证码。

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\')

 

3、视图函数 

使用io.BytesIO对象将验证码图片转化为二进制形式,直接作为响应返回前端。设置首部字段的内容格式,这样二进制的内容就能以图形形式在页面中显示。验证码字符串保存在flask.session对象中,对session的操作就像处理字典一样。程序内部使用设置中的SECRET_KEY对session数据加密后,存储在cookie中。

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中保存的验证码字符串都转换成小写后再作判断。

@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)

 

4、前端

在前端中加入了验证码图形的路径,该路径指定为生成图形响应的视图函数。当点击验证码图片时,验证码会予以更新。

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

 

调整下布置,最终登录表单会显示成这个样子:

下面是不同方式生成的验证码:

a. 无特效 b. 增加高斯模糊 c. 增加划线

以上是关于Flask博客开发——登录验证码的主要内容,如果未能解决你的问题,请参考以下文章

flask验证登录学习过程---准备

在Python中用Request库模拟登录:博客园(简单加密,无验证码)

Haytham个人博客开发日志 -- Flask+Vue基于token的登录状态与路由管理

从0开发一个Django博客系统

django-博客系统-登录验证码

登录界面更换验证码图片