前段时间的某一天,我这个万年没几个人光临,门可罗雀的网站,突然被刷垃圾评论,手机的邮箱一直给我发新消息提醒,着实搞得我有点烦,但又没什么时间搞,所以就先暂时把评论功能给关了。最近就趁着清明假期弄了一个简单的评论验证码系统,下面就分享一下我的设计思路,希望对小伙伴们有帮助。

思路一览

1、准备一个验证码的路由,每次访问时,随机生成一个由大小写字母或者数字组成的四位验证码,将其储存在用户的session当中,如果之前有则会覆盖,然后返回一个base64二进制流的图片数据。

2、每次访问文章页面,自动用ajax的方式访问一次验证码路由,更新session,并返回验证码图片,将图片更新于对应的位置。

3、如果看不清验证码,点击验证码时,又重新用ajax形式访问一次验证码路由,更新session,也更新对应的验证码图片。

4、评论提交时,判断输入的验证码如果与session中的一致则将评论写入数据库中。

实现

验证码路由

验证码路由主要分为 生成随机四位验证码验证码图片生成器验证码路由(写入session并返回图片)

生成随机验证码

import random
random_base="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

def random_vc():
    vc_pieces=random.sample(random_base,4)
    return ''.join(vc_pieces)

验证码图片生成器 (这里我们需要返回图片的base64值,这样前端会方便显示)

from PIL import Image,ImageDraw,ImageFont

def random_text_color():
    return (random.randint(127,255),random.randint(127,255),random.randint(127,255))

def random_bg_color():
    return (random.randint(32,127),random.randint(32,127),random.randint(32,127))

def word2pic(word):#根据验证码生成验证码图片
    image=Image.new('RGB',(100,30),random_bg_color())
    font=ImageFont.truetype('arial.ttf',15)
    draw=ImageDraw.Draw(image)
    for t in range(4):
        draw.text((25*t+10,5),word[t],font=font,fill=random_text_color())

    bytesIO=BytesIO()
    image.save(bytesIO,format='JPEG')

    return base64.b64encode(bytesIO.getvalue()).decode()

验证码路由

from flask import Flask,request,session
...

@app.route('/get_vc')
def get_vc():
    vc=random_vc()#生成随机验证码
    session['comment_vc']=vc#写入session
    vc_image=word2pic(vc)#生成验证码图片数据
    return 'data:image/jpeg;base64,'+vc_image#返回图片数据

以上便是验证码路由的部分了,接下来我们来写一下前端的部分。

前端部分

post.html 我的网站评论是位于文章页的,所以在文章页的基础上修改。

......
<div id="comments" class="comments_title">评论</div>

<div class="row">
    <div class="col-md-5 col-sm-8">
        <form method="POST" class="form">

            <div class="form-group  required">
                <label class="control-label" for="name">昵称</label>
                <input class="form-control" name="name" required="" type="text" value="">
            </div>

            .....

            <div class="form-group  required">
                <label class="control-label" for="verificationCode">验证码</label>
                <div class="row">
                    <div class="col-xs-6">
                        <input class="form-control" name="verificationCode" required="" type="text" value="">
                    </div>
                    <div class="col-xs-5">
                        <img src="" class="vc_image" id="vc_image" onclick="javascript:fresh_vc();">
                    </div>
                </div>
            </div>

            .....

            <input class="btn btn-default" id="submit" name="submit" type="submit" value="提交">
        </form>
    </div>
</div>

<script>
    function fresh_vc(){
        $.get('/get_vc',function(data){
            $('#vc_image').attr('src',data);
        })
    }

    fresh_vc();
</script>
......

这样每次访问文章页时,会自动调用一次fresh_vc()函数,更新session中的验证码,并返回图片,如果图片看不清,点击图片也会执行fresh_vc()

验证部分

这一部分还是比较简单的,就是判断用户提交的表单中name为verificationCode的值是否与session中的一致。注意输入的验证码与session中的验证码需要同时转化为大写或者小写再进行判断。

@app.route('/post/<int:id>',methods=['GET','POST'])
def post(id):
    ...
    if request.method=='POST':
        if request.form['verificationCode'].lower()==session.get('comment_vc').lower():
            name=request.form['name']
            email=request.form['email']
            content=request.form['content']
            comment=Comment(name=name,email=email,content=content)
            db.session.add(comment)
            db.session.commit()
            flash('评论成功')
        else:
            flash('评论失败,验证码错误')
    ...

至此,一个简单的评论验证码系统就完成了。

其他

另外由于现在已经出现了许多开源的可以自动识别简单验证码的工具,所以为了防止出现这种情况,也可以在图片上多做一些手脚,比如扭曲、模糊等等,甚至是生成公式的验证图片等等。另外还可以在验证码的右侧添加一个即时验证的状态,对用户更加友好,这个用ajax搭配一个验证路由就可以搞定。也希望上面上面的分享会对你有所帮助,有错误或者意见也欢迎评论指出噢。

评论

Felix 管理员

好家伙,距离上一篇文章竟已过去了快4个月了。

回复

  • 最新随笔

  • 这个桥去年来看的时候貌似还没有
  • 中秋经典BGM:滴滴滴
  • 猫确实喜欢在各种犄角旮旯里睡觉
  • 尝试让DALLE生成一些连续的精灵图,让gpt帮忙生成一些提示词,如果能稳定输出的话就很强大了。
    让gpt帮忙生成的DALLE提示词
    "Generate a pixel art sprite sheet of a character walking in four directions (north, south, east, west) in a retro video game style."
    "Create a series of pixel art frames showing a character performing different actions like walking, running, jumping, and attacking in a classic 2D game aesthetic."
  • 路过别人山庄的门口,被一条大黑狗边叫边追过来,幸好骑电动车,不然还不一定跑得过,哈哈哈哈哈哈哈哈哈哈。
  • 最近两周也没咋出去玩,主要也是觉得没啥好玩的(笑哭)。看完布莱恩阿瑟的《复杂经济学》后,里面那个酒吧问题勾起我的兴趣,最近空了就花了些时间实现个python版本,顺便搞了篇博文,很享受这种新知识能和已有知识碰撞的感觉。(配张前段时间拍的图片,梧桐山门口前面那条路,挺漂亮的)
  • 盐田港夜景
  • 为啥这猫总喜欢喝杯子里的水