前段时间的某一天,我这个万年没几个人光临,门可罗雀的网站,突然被刷垃圾评论,手机的邮箱一直给我发新消息提醒,着实搞得我有点烦,但又没什么时间搞,所以就先暂时把评论功能给关了。最近就趁着清明假期弄了一个简单的评论验证码系统,下面就分享一下我的设计思路,希望对小伙伴们有帮助。
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搭配一个验证路由就可以搞定。也希望上面上面的分享会对你有所帮助,有错误或者意见也欢迎评论指出噢。