目录
templates/login/login.html
utils/code.py
views/login.py
验证码
生成验证码
code.py
应用验证码
views.py
login.html
templates/login/login.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="{% static 'css/bootstrap.css'%}">
</head>
<body>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;}html {height: 100%;}body {height: 100%;}.container {height: 100%;width: 100%;background-image: linear-gradient(to right, #fbc2eb, #a6c1ee);}.login-wrapper {background-color: #fff;width: 358px;height: 588px;border-radius: 15px;padding: 0 50px;position: relative;left: 50%;top: 50%;transform: translate(-50%, -50%);}.header {font-size: 38px;font-weight: bold;text-align: center;line-height: 200px;}.input-item {display: block;width: 100%;margin-bottom: 20px;border: 0;padding: 10px;border-bottom: 1px solid rgb(128, 125, 125);font-size: 15px;outline: none;}.input-item:placeholder {text-transform: uppercase;}.btn {text-align: center;padding: 10px;width: 100%;margin-top: 40px;background-image: linear-gradient(to right, #a6c1ee, #fbc2eb);color: #fff;}.msg {text-align: center;line-height: 88px;}a {text-decoration-line: none;color: #abc1ee;}</style>
</head>
<body><div class="container"><div class="login-wrapper"><div class="header">Login</div><div class="form-wrapper"><form method="post" novalidate>{% csrf_token %}<div class="col-md-12">{{ form.username }}<span style="color: red">{{ form.password.errors.0 }}</span>{{ form.password }}</div><div class="col-md-7">{{ form.code }}<span style="color:red;">{{ form.code.errors.0 }}</span></div><div class="col-md-5"><button style="border: none"><img src="/image/code/"></button></div><button class="btn" type="submit">Login</button></form></div></div></div>
</body>
</html></body>
</html>
utils/code.py
# -*- coding:utf-8 -*-
# pip install pillow==9.4.0from PIL import Image, ImageFont, ImageDraw
from random import choice,randintdef create_image_content():# 创建一张图片img = Image.new(mode="RGB", size=(110, 40), color=(255, 255, 255))# 创建一个画笔draw = ImageDraw.Draw(img, mode="RGB")font = ImageFont.truetype("./simkai.ttf", size=30)# 验证码出现的字符text = "ABCDEFG23456789"# 存放四位验证码的字符串image_text = ""# 生成几位数的验证码,就循环几次for num in range(4):image_text += choice(text)# 每次遍历的时候,将字符添加到图片上x = 15for i in image_text:# 为每一位验证码添加不同颜色R = str(randint(0, 255))G = str(randint(0, 255))B = str(randint(0, 255))draw.text((x, 5),text=i,font=font,fill=f"rgb({R},{G},{B})")x += 20# 添加干扰线条for i in range(1, randint(3, 6)):x1, y1 = randint(0, 110), randint(0, 40)x2, y2 = randint(0, 110), randint(0, 40)R = str(randint(0, 255))G = str(randint(0, 255))B = str(randint(0, 255))draw.line((x1, y1, x2, y2),fill=f"rgb({R},{G},{B})", width=2)# 添加干扰点for i in range(1, randint(30, 50)):x1, y1 = randint(0, 110), randint(0, 40)R = str(randint(0, 255))G = str(randint(0, 255))B = str(randint(0, 255))draw.point([x1, y1], fill=f"rgb({R},{G},{B})")# print(image_text)# img.save("code.png")# print(img)return [img, image_text]
views/login.py
# -*- coding:utf-8 -*-
from django.shortcuts import render, redirect,HttpResponse
from demo_one.utils import pwd_data
from django import forms
from demo_one import models
from demo_one.utils.code import create_image_contentclass LoginForm(forms.Form):username = forms.CharField(label="用户名", widget=forms.TextInput(attrs={"class": "input-item", "autocomplete": "off", "placeholder": "请输入用户名"}))password = forms.CharField(label="密码", widget=forms.PasswordInput(attrs={"class": "input-item", "autocomplete": "off", "placeholder": "请输入密码"}))code = forms.CharField(label="验证码", widget=forms.TextInput(attrs={"class": "input-item", "autocomplete": "off", "placeholder": "请输入验证码"}))def clean_password(self):pwd = self.cleaned_data.get("password")# print(self.cleaned_data)return pwd_data.md5(pwd)def login(request):if request.method == "GET":form = LoginForm()return render(request, "login/login.html", {"form": form})form = LoginForm(data=request.POST)if form.is_valid():# 去数据库进行校验# print(form.cleaned_data)# 使用pop删除,pop返回被删除的值user_input_code = form.cleaned_data.pop("code")code = str(request.session.get("image_code"))# print("我自己输入的是:", user_input_code)# print("系统生成的是:", code)if user_input_code.upper() != code.upper():form.add_error("code", "验证码错误")return render(request, "login/login.html", {"form": form})admin_object = models.Adminrole.objects.filter(**form.cleaned_data).first()if not admin_object:# 给输入框添加一个错误提示form.add_error("password", "用户名或密码错误")return render(request, "login/login.html", {"form": form})# 登录成功之后# 将登录信息存储在session当中request.session["info"] = {"id": admin_object.id, "username": admin_object.username,"password": admin_object.password, "role": admin_object.role}# 时效性request.session.set_expiry(60 * 60 * 24 * 30)# 登录成功后跳转到首页return redirect("/")return render(request, "login/login.html", {"form": form})def logout(request):request.session.clear()return redirect("/login/")from io import BytesIOdef image_code(request):image, text = create_image_content()request.session["image_code"] = textrequest.session.set_expiry(60)stream = BytesIO()image.save(stream, "png")return HttpResponse(stream.getvalue())
验证码
生成验证码
-
code.py
# -*- coding:utf-8 -*- # pip install pillow==9.4.0 from PIL import Image, ImageFont, ImageDraw from random import choice,randint def create_image_content():# 创建一张图片img = Image.new(mode="RGB", size=(110, 40), color=(255, 255, 255))# 创建一个画笔draw = ImageDraw.Draw(img, mode="RGB")font = ImageFont.truetype("./simkai.ttf", size=30) # 验证码出现的字符text = "ABCDEFG23456789" # 存放四位验证码的字符串image_text = ""# 生成几位数的验证码,就循环几次for num in range(4):image_text += choice(text) # 每次遍历的时候,将字符添加到图片上x = 15for i in image_text:# 为每一位验证码添加不同颜色R = str(randint(0, 255))G = str(randint(0, 255))B = str(randint(0, 255))draw.text((x, 5),text=i,font=font,fill=f"rgb({R},{G},{B})")x += 20 # 添加干扰线条for i in range(1, randint(3, 6)):x1, y1 = randint(0, 110), randint(0, 40)x2, y2 = randint(0, 110), randint(0, 40)R = str(randint(0, 255))G = str(randint(0, 255))B = str(randint(0, 255))draw.line((x1, y1, x2, y2),fill=f"rgb({R},{G},{B})", width=2) # 添加干扰点for i in range(1, randint(30, 50)):x1, y1 = randint(0, 110), randint(0, 40)R = str(randint(0, 255))G = str(randint(0, 255))B = str(randint(0, 255))draw.point([x1, y1], fill=f"rgb({R},{G},{B})") # print(image_text)# img.save("code.png")# print(img)return [img, image_text]
应用验证码
-
views.py
def login(request):if request.method == "GET":form = LoginForm()return render(request, "login/login.html", {"form": form}) form = LoginForm(data=request.POST)if form.is_valid():# 去数据库进行校验# print(form.cleaned_data)# 使用pop删除,pop返回被删除的值user_input_code = form.cleaned_data.pop("code")code = str(request.session.get("image_code"))# print("我自己输入的是:", user_input_code)# print("系统生成的是:", code)if user_input_code.upper() != code.upper():form.add_error("code", "验证码错误")return render(request, "login/login.html", {"form": form})admin_object = models.Adminrole.objects.filter(**form.cleaned_data).first()if not admin_object:# 给输入框添加一个错误提示form.add_error("password", "用户名或密码错误")return render(request, "login/login.html", {"form": form})# 登录成功之后# 将登录信息存储在session当中request.session["info"] = {"id": admin_object.id, "username": admin_object.username,"password": admin_object.password, "role": admin_object.role}# 时效性request.session.set_expiry(60 * 60 * 24 * 30)# 登录成功后跳转到首页return redirect("/")return render(request, "login/login.html", {"form": form}) def logout(request):request.session.clear()return redirect("/login/") from io import BytesIO def image_code(request):image, text = create_image_content()request.session["image_code"] = textrequest.session.set_expiry(60) stream = BytesIO()image.save(stream, "png")return HttpResponse(stream.getvalue())
login.html
-
login.html{% load static %} <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="{% static 'css/bootstrap.css'%}"> </head> <body> <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;}html {height: 100%;}body {height: 100%;}.container {height: 100%;width: 100%;background-image: linear-gradient(to right, #fbc2eb, #a6c1ee);}.login-wrapper {background-color: #fff;width: 358px;height: 588px;border-radius: 15px;padding: 0 50px;position: relative;left: 50%;top: 50%;transform: translate(-50%, -50%);}.header {font-size: 38px;font-weight: bold;text-align: center;line-height: 200px;}.input-item {display: block;width: 100%;margin-bottom: 20px;border: 0;padding: 10px;border-bottom: 1px solid rgb(128, 125, 125);font-size: 15px;outline: none;}.input-item:placeholder {text-transform: uppercase;}.btn {text-align: center;padding: 10px;width: 100%;margin-top: 40px;background-image: linear-gradient(to right, #a6c1ee, #fbc2eb);color: #fff;}.msg {text-align: center;line-height: 88px;}a {text-decoration-line: none;color: #abc1ee;}</style> </head> <body><div class="container"><div class="login-wrapper"><div class="header">Login</div><div class="form-wrapper"><form method="post" novalidate>{% csrf_token %}<div class="col-md-12">{{ form.username }}<span style="color: red">{{ form.password.errors.0 }}</span>{{ form.password }}</div><div class="col-md-7">{{ form.code }}<span style="color:red;">{{ form.code.errors.0 }}</span></div><div class="col-md-5"><button style="border: none"><img src="/image/code/"></button> </div> <button class="btn" type="submit">Login</button></form></div> </div></div> </body> </html> </body> </html>