• 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. 增加划线
  • 相关阅读:
    Python学习 Day 1-简介 安装 Hello world
    R Programming week2 Functions and Scoping Rules
    R in action读书笔记(6)-第七章:基本统计分析(中)
    R in action读书笔记(5)-第七章:基本统计分析
    Redis进阶应用:Redis+Lua脚本实现复合操作
    一个项目的SpringCloud微服务改造过程
    中间件增强框架之-CaptureFramework框架
    关系型数据库全表扫描分片详解
    AI中台——智能聊天机器人平台的架构与应用(分享实录)
    如何设计实时数据平台(设计篇)
  • 原文地址:https://www.cnblogs.com/ik-heu/p/8840518.html
Copyright © 2020-2023  润新知