- 1.我们在登录的时候,经常看到输入用户名、密码之外。还需要输入验证码。这个验证码是怎么实现的呢?
- 2.前端
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}">
<style>
.account {
width: 400px;
border: 1px solid #dddddd;
border-radius: 5px;
box-shadow: 5px 5px 20px #aaa;
margin-left: auto;
margin-right: auto;
margin-top: 100px;
padding: 20px 40px;
}
.account h2 {
margin-top: 10px;
text-align: center;
}
</style>
</head>
<body>
<div class="account">
<h2>用户登录</h2>
<form method="post" novalidate>
{% csrf_token %}
<div class="form-group">
<label>用户名</label>
{{ form.username }}
<span style="color: red;">{{ form.username.errors.0 }}</span>
</div>
<div class="form-group">
<label>密码</label>
{{ form.password }}
<span style="color: red;">{{ form.password.errors.0 }}</span>
</div>
<div class="form-group">
<label for="id_code">图片验证码</label>
<div class="row">
<div class="col-xs-7">
{{ form.code }}
<span style="color: red;">{{ form.code.errors.0 }}</span>
</div>
<div class="col-xs-5">
<img id="image_code" src="/image/code/" style="width: 125px;">
</div>
</div>
</div>
<input type="submit" value="登 录" class="btn btn-primary">
</form>
</div>
</body>
</html>
- 3.生成图片验证码,pip install pillow,使用第三方模块pillow
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
def check_code(width=120, height=30, char_length=5, font_file='Monaco.ttf', font_size=28):
code = []
img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
draw = ImageDraw.Draw(img, mode='RGB')
def rndChar():
"""
生成随机字母
:return:
"""
# return str(random.randint(0, 9))
return chr(random.randint(65, 90))
def rndColor():
"""
生成随机颜色
:return:
"""
return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))
# 写文字
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())
# 写干扰点
for i in range(40):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
# 写干扰圆圈
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())
# 画干扰线
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 = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
return img, ''.join(code)
# if __name__ == "__main__":
# img, code_str = check_code()
# print(code_str)
#
# with open('code.png', 'wb') as f:
# img.save(f, format='png')
- 4.访问登录界面时,会访问/image/code,执行视图函数image_code
def image_code(request):
"""生成图片验证码"""
img,code_string = check_code()
# print(code_string)
# 写入到自己的session中(以便于后续获取验证码再进行校验)
request.session['image_code'] = code_string
# 给Session设置60s超时
request.session.set_expiry(60)
stream = BytesIO()
img.save(stream, 'png')
return HttpResponse(stream.getvalue())
- 5.登录时,增加图片验证码的校验
from django.shortcuts import render, redirect,HttpResponse
from app01 import models
from app01.utils.bootstrap import BootStrapForm
from django import forms
from io import BytesIO
from app01.utils.encrypt import md5
from app01.utils.code import check_code
class LoginForm(BootStrapForm):
username = forms.CharField(
label="用户名",
widget=forms.TextInput,
required=True
)
password = forms.CharField(
label="密码",
widget=forms.PasswordInput(render_value=True), # 错误提示的时候,内容不清空
required=True # 必填,默认为True
)
code = forms.CharField(
label="验证码",
widget=forms.TextInput,
required=True
)
def clean_password(self):
pwd = self.cleaned_data.get("password")
return md5(pwd)
def login(request):
if request.method == "GET":
form = LoginForm()
return render(request,"login.html",{"form":form})
form = LoginForm(data = request.POST)
if form.is_valid():
# print(form.cleaned_data) # {'username': 'xwl', 'password': '1cd19cf980df7815e8303ab92ff66296'}
# print(form.cleaned_data) # {'username': 'xwl', 'password': '1cd19cf980df7815e8303ab92ff66296',"code":xxx}
# 校验图片验证码
user_input_code = form.cleaned_data.pop("code") # 剔除图片,方便后面的用户密码校验
code = request.session.get("image_code","") # 获取生成的code
# print(code)
if code.upper() != user_input_code.upper():
form.add_error("code","验证码错误")
return render(request,"login.html",{"form":form})
# 去数据库校验用户名和密码是否正确,获取用户对象、None
# admin_object = models.Admin.objects.filter(username=xxx, password=xxx).first()
admin_object = models.Admin.objects.filter(**form.cleaned_data).first()
if not admin_object:
form.add_error("password", "用户名或密码错误") # 主动在username字段显示错误信息
# form.add_error("username", "用户名或密码错误")
return render(request, 'login.html', {'form': form})
# 用户名和密码正确
# 网站生成随机字符串,写入浏览器的cookie中,再写入到session中
request.session["info"] = {'id': admin_object.id, 'name': admin_object.username}
# sesion可以保存7天
request.session.set_expiry(60 * 60 * 24 * 7)
return redirect('/admin/list/')
return render(request,"login.html",{"form":form})