验证码是一种区分用户是计算机还是人的公共全自动程序
可以防止:恶意破解密码、刷票、论坛灌水,有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试等
分类
当今验证码各种不同的类别很多,常见的如下:
-
普通型:随机多个(一般是4个)字母、数字和中文的图片,可能加一些干扰项
-
问答型:图片中显示一个问题,计算题、选择题四选一、问答题
-
拖动行为型:拖动一个小图片到一个拼图中
实现思路
大部分的验证码验证的思路都是这样的:
-
客户端发送获取验证码的请求
-
服务端接收到验证码请求后,生成对应的验证码和正确答案
-
服务端将验证码的正确答案保存到会话对象当中
-
服务端将验证码返回到客户端
-
客户端看到验证码后:
- 如果看不清等原因,可以重新获取,那么就重新回到第1步
- 正确显示后,输入答案,提交答案到服务端
-
服务端接收到验证码答案后,和保存在会话对象中的正确答案比对,正确就通过验证,失败则返回错误提示
实现
登录环境的搭建:
使用django的admin作为用户
from django.shortcuts import render,redirect
from django.conf import settings
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
# Create your views here.
from django.views import View
# 登录视图类
class LoginView(View):
# 处理GET请求
def get(self, request):
login_err = request.session.get('login_err', None) # 获取登录错误信息
request.session.delete('login_err') # 删除登录错误信息
return render(request, 'login.html',{'login_err':login_err})
# 处理POST请求
def post(self, request):
username = request.POST.get('user', None)
password = request.POST.get('pwd', None)
user = authenticate(username=username, password=password)
# 验证用户名和密码是否正确
if user is not None:
login(request, user) # 将用户信息添加到session中
return redirect('index')
else:
request.session['login_err'] = '用户名或密码错误'
return redirect('login')
# 登出视图函数
def logout_view(request):
logout(request) # 清除session中的用户信息
return redirect('login')
# 如果用户未登录重定向到login页面
@login_required(login_url='/login/')
def check_login(request):
return render(request, 'index.html')
创建好登录之后就是验证码的生成
验证码图片生成
import random
import os
from PIL import Image,ImageDraw,ImageFont,ImageFilter
def random_str(length=4):
""" 随机字符串 默认长度 4
:param length: 默认长度 4
:return:
"""
return ''.join(random.sample(string.ascii_letters, length))
# 生成颜色
def random_color():
# RGB
return random.randint(0,255),random.randint(0,255),random.randint(0,255)
# 生成验证码
def generate_captcha(width=160,height=40,length=4):
# 创建一个空白图片
image = Image.new('RGB',(width,height),color=(255,255,255))
# 获取画布里的内容
code = random_str()
# 获取画笔
draw = ImageDraw.Draw(image)
# 随机颜色的填充
for x in range(0,width,2):
for y in range(height):
draw.point((x,y),fill=random_color())
# 获取字体文件
font = ImageFont.truetype(os.path.join(os.path.dirname(__file__),'SIMHEI.TTF'),size=30)
# 将内容写入图片
for t in range(length):
# 通过画笔工具写入内容
draw.text((40*t+5,5),code[t],font=font,fill=random_color())
# 图片的模糊
image = image.filter(ImageFilter.BLUR)
# 返回图片,验证码
return image,code
from io import BytesIO
from django.http import HttpResponse
from django.shortcuts import render,redirect
from django.conf import settings
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from .create_caprcha import generate_captcha
# Create your views here.
from django.views import View
# 登录视图类
class LoginView(View):
# 处理GET请求
def get(self, request):
login_err = request.session.get('login_err', None) # 获取登录错误信息
request.session.delete('login_err') # 删除登录错误信息
return render(request, 'login.html',{'login_err':login_err})
# 处理POST请求
def post(self, request):
username = request.POST.get('user', None) # 获取用户名和密码
password = request.POST.get('pwd', None) # 获取用户名和密码
input_code = request.POST.get('code', '') # 获取用户输入的验证码
right_code = request.session.get('captcha_code', '') # 获取session中的验证码
# 验证用户输入的验证码是否正确
if input_code == right_code:
user = authenticate(username=username, password=password)
# 验证用户名和密码是否正确
if user is not None:
login(request, user) # 将用户信息添加到session中
return redirect('index')
else:
request.session['login_err'] = '用户名或密码错误'
return redirect('login')
else:
request.session['login_err'] = '验证码不正确'
return redirect('login')
# 登出视图函数
def logout_view(request):
logout(request) # 清除session中的用户信息
return redirect('login')
# 如果用户未登录重定向到login页面
@login_required(login_url='/login/')
def check_login(request):
return render(request, 'index.html')
# 验证码测试视图函数
def captcha_test(request):
img,code = generate_captcha() # 生成验证码
print(code)
request.session['captcha_code'] = code # 将验证码保存到session中
buf = BytesIO() # 创建一个BytesIO对象,用于存储验证码图片
img.save(buf,'png') # 将验证码图片保存到BytesIO对象中
return HttpResponse(buf.getvalue()) # 返回验证码图片