开头
在登陆时添加一个验证码校验功能,当邮箱激活后,用户输入正确的验证码之后才能登录系统。
1.生成图片
安装pillow
模块
Pillow
是一个常用的图像处理库,它提供了丰富的图像处理功能,包括打开、保存、裁剪、调整大小、旋转、滤镜等操作。
pip install pillow
生成验证码图片,这个代码可以直接拿来用
需要注意的是,这里需要导入一个字体文件,字体文件可以从电脑获取
路径:C:\Windows\Fonts
,然后选择一个就可以,我选择的是楷体,然后把STKAITI.TTF
这个文件放在项目的根目录下
from PIL import Image, ImageFilter,ImageDraw,ImageFont
import random
def check_code(width=120, height=30, char_length=5, font_file='STKAITI.TTF', font_size=28):
code = []
# 创建了一个新的 RGB 模式的图片对象 img,背景颜色为白色
img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
# 使用 ImageDraw 模块的 Draw 函数创建了一个绘图对象 draw,用于在图片上绘制文字和图形。
draw = ImageDraw.Draw(img, mode='RGB')
def rndChar():
"""
生成随机字母
:return:
"""
return chr(random.randint(65, 90))
def rndColor():
"""
生成随机颜色
:return:
"""
return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))
# 使用指定的字体文件和字体大小创建了一个字体对象 font,用于绘制文字
font = ImageFont.truetype(font_file, font_size)
for i in range(char_length):
char = rndChar()
code.append(char)
h = random.randint(0, 4)
draw.text([i * width / char_length, h], char, font=font, fill=rndColor())
# draw.point() 在图片上绘制一些干扰点,数量为 40 个
for i in range(40):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
# draw.arc() 绘制一些干扰圆圈,数量也为 40 个
for i in range(40):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())
# draw.line() 绘制五条干扰线,起点和终点的坐标都是随机生成的
for i in range(5):
x1 = random.randint(0, width)
y1 = random.randint(0, height)
x2 = random.randint(0, width)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=rndColor())
# img.filter() 对图片进行边缘增强的滤镜处理,并将处理后的图片对象和验证码字符拼接成一个元组返回
img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
return img, ''.join(code)
if __name__ == '__main__':
# 1. 直接打开
# img,code = check_code()
# img.show()
# 2. 写入文件
img,code = check_code()
with open('code.png','wb') as f:
img.save(f,format='png')
# 3. 写入内存(Python3)
# from io import BytesIO
# stream = BytesIO()
# img.save(stream, 'png')
# stream.getvalue()
# 4. 写入内存(Python2)
# import StringIO
# stream = StringIO.StringIO()
# img.save(stream, 'png')
# stream.getvalue()
pass
效果如下
2.在视图函数中生成验证码函数
def codevalidate(request):
# 调用生成验证码图片的函数
img, code_string = check_code()
print('验证码:', code_string)
# 写入内存
from io import BytesIO
# 在内存中图片以字节流的形式传输
stream = BytesIO()
# 写入到自己的session中,以便后续获取验证码进行校验(每个用户自己的验证码)
request.session['imagecode'] = code_string
# 给session设置超时时间
request.session.set_expiry(60 * 60 * 24 * 7)
img.save(stream, 'png')
return HttpResponse(stream.getvalue())
3.修改中间件,允许非登录用户访问图片URL
因为我设置了中间件,所以修改一下代码,放行路径为/bossApp/codevalidate/
的路由
class UserMiddleWare(MiddlewareMixin):
def process_request(self,request):
path = request.path_info
print(path)
# 0.如果请求路由是登录或注册,继续执行
if path in ['/bossApp/login/','/bossApp/register/','/bossApp/codevalidate/']:
return
# 1.读取当前访问用的session信息,如果能读到,则继续向下执行
info_dict = request.session.get("username")
print(info_dict)
if info_dict:
return
# 2.如果没有登录,提示登录
return redirect('/bossApp/login/')
def process_response(self,request,response):
print("UserMW leave here")
return response
4.校验图片验证码
通过从session中获取验证码与输入的验证码进行比较
def login(request):
if request.method == "GET":
return render(request, 'login.html')
else:
username = request.POST.get('username')
pwd = request.POST.get('password')
email = request.POST.get('email')
code = request.POST.get('code')
# 创建md5对象
md5 = hashlib.md5()
# 对字符串进行编码
md5.update(pwd.encode())
# 加密
pwd = md5.hexdigest()
try:
# 判段加密后的密码是否相等
user = User.objects.get(username=username, password=pwd)
# 邮箱是否正确
if user.email == email:
# 邮箱激活
if user.is_active:
# 判段验证码是否正确
img_code = request.session.get('imagecode')
print(code,img_code)
if code.upper() != img_code.upper():
return errorResponse(request, '验证码不正确!!')
else:
# 密码相等的话设置session,保存该用户的一次会话
request.session['username'] = user.username
# print('session-------username',request.session.get('username'))
# 跳转到首页
return redirect('/bossApp/home')
else:
return errorResponse(request, '该用户未激活,请先激活!!')
return errorResponse(request, '邮箱不存在,重新输入!!')
except:
return errorResponse(request, '用户名或密码错误!!')
贴一下刷新验证码,使用js重新加载一下验证码的路由就好了
部分html代码
<div style="margin-left: 195px;margin-top: -43px">
{# 动态生成验证码图片 #}
<img style="height: 41px" id="img_code" src="/bossApp/codevalidate/">
</div>
<div style="margin-right: -195px;margin-top: 3px;">
<a href="#" id="refresh-link"
style="font-size: 12px;">看不清,换一张</a>
</div>
</div>
</div>
js代码
<script>
document.getElementById("refresh-link").addEventListener("click", function(e) {
e.preventDefault(); // 阻止默认的链接点击行为
var imgCode = document.getElementById("img_code");
imgCode.src = "/bossApp/codevalidate/?t=" + new Date().getTime(); // 添加时间戳来避免缓存
});