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

思路一览

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个月了。

回复

  • 最新随笔

  • 对我来说,写东西很好的一点是,自己写的东西,后面基本都会再看,一遍或者很多遍。这样就可以很好地发现自己之前的漏洞,并看看现在有什么变化。
  • 前段时间应该是百度更新了页面结构,那个黑帽泛目录网站我也没有去更新代码,就导致了文章页没有相关推荐,没想到这时候谷歌开始收录了,而且效果还不错。其实之前在谷歌一直不收录的时候就有怀疑过没有尽头的相关推荐很可能是导致不收录的原因,不过也一直没有去管它,而这次误打误撞的收录也恰恰证实了这个想法。(btw,其实这个网站从出现固定链接开始叫泛目录应该不太准确)
  • 最近吉他谱网站iloveguitar上线了,这几天在填充一些内容花了一些时间,这个网站也是使用flask作为后端框架的,前端UI框架使用的是bootstrap4,喜欢吉他的小伙伴欢迎来这里逛一逛哟,有什么建议欢迎在留言板提一下哟。
  • 那个泛目录网站发布了几个星期了,百度没怎么来爬,收了一个首页,谷歌直接就不收了,倒是一个查外链的网站天天来爬(笑哭),还有建议一点就是泛目录还是用在有建站历史的域名比较好(因为已经过了审核期),新域名就尽量不要用了。
  • 刚刚又发了一篇,最近文章百度都不太收录,orz,哈哈
  • 之前那个用python做的静态资源服务器,我又发现了一大用处,现在我都用来在局域网里的不同电脑之间传输文件,真的好用哈哈
  • 今天交换到了博客有史以来第一条友情链接
  • 刚刚更新了一下博客,修复了一些bug,添加了一个项目页