当前位置: 首页 > news >正文

Django之验证码功能

验证码功能

目录

1.绘制验证码

2.在登录页面里面实现验证码的功能

3.代码展示集合

这篇文章, 内容不是很多, 不过验证码, 是在网页里面比较常见的功能, 所有我们还是要掌握它!!!

一、绘制验证码

绘制验证码, 我们需要用到图像, 然后在图片里面插入要输入的验证码的文字和文字周边的一些干扰线条或点。

我们在utils文件夹下面, 新建一个code.py文件, 这个文件里面写的代码, 就是生成验证码的代码。

code.py:

from PIL import Image, ImageDraw, ImageFont
from random import randint, choicedef create_image_content():# 创建画布# mode='RGB'代表使用RGB, size代表画布大小, color代表颜色, 用的rgb颜色。image = Image.new(mode='RGB', size=(110, 40), color=(255, 255, 255))# 创建画笔draw = ImageDraw.Draw(image, mode='RGB')font = ImageFont.truetype('simhei.ttf', size=30)# 验证码的内容, 都是从text字符串的范围之内生成的text = "ABCDEFG123456"# image_text是用来存储生成的验证码的内容image_text = ""for i in range(4):# 在text里面随机挑选一个元素然后添加到image_text里面image_text += choice(text)# 在画布(图像)上画四个文字, 这四个文字就是我们生成的验证码的内容。x = 17for 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, fill=f"rgb({R}, {G}, {B})", font=font)x += 20# 在画布(图像)上面增加4到5条干扰线。for i in range(1, randint(4, 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)# image.save('code.png') 验证码生成后, 把图片保存下来。# 返回画布(图片)和验证码图片里面的内容return [image, image_text]
# 调用函数
# create_image_content()

运行结果:

在这里插入图片描述

在相同的路径下, 会出现code.png, 这个就是我们生成的验证码的图片。

注意: 如果要运行此文件, 需要把我已经注释的image.save(‘code.png’)和create_image_content()给它去掉。然后再运行才会有结果。给它注释掉的原因是之后我们用到自己写的创建验证码的功能的时候, 需要把image.save(‘code.png’)和create_image_content()注释掉。

打开code.png:

在这里插入图片描述

验证码生成成功!!!

二、在登录页面里面实现验证码的功能

我们打开login.py, 写验证码生成的函数:

login.py:

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())

这个就是生成验证码的函数。

然后, 我们给它配置路由:

urls.py:

"""project_simple URL ConfigurationThe `urlpatterns` list routes URLs to views. For more information please see:https://docs.djangoproject.com/en/4.1/topics/http/urls/
Examples:
Function views1. Add an import:  from my_app import views2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views1. Add an import:  from other_app.views import Home2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf1. Import the include() function: from django.urls import include, path2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from project_one.views import depart, user, assets, admin_role, loginurlpatterns = [# path('admin/', admin.site.urls),path("", depart.index, name="index"),path("depart/", depart.depart, name="depart"),path("depart/add/", depart.add_depart, name="add_depart"),path("depart/<int:nid>/modify/", depart.depart_modify, name="depart_modify"),path("depart/<int:nid>/del/", depart.del_depart, name="del_depart"),path("user/", user.user_info, name="user_info"),path("user/add/", user.user_add, name="user_add"),path("user/<int:nid>/modify/", user.user_modify, name="user_modify"),path("user/<int:nid>/del/", user.user_del, name="user_del"),path("user/add/modelform", user.user_add_modelform, name="user_add_modelform"),path("user/<int:nid>/modify/modelform", user.user_modify_modelform, name="user_modify_modelform"),path("assets_list/", assets.assets, name="assets"),path("assets/add/", assets.assets_add, name="assets_add"),path("assets/<int:nid>/modify/", assets.assets_modify, name="assets_modify"),path("assets/<int:nid>/del/", assets.assets_del, name="assets_del"),path("admin_list/", admin_role.admin, name="admin"),path("admin/add/", admin_role.admin_add, name="admin_add"),path("admin/<int:nid>/modify/", admin_role.admin_modify, name="admin_modify"),path("admin/<int:nid>/reset/pwd/", admin_role.admin_reset_pwd, name="admin_reset_pwd"),path("admin/<int:nid>/del/", admin_role.admin_del, name="admin_del"),path("login/", login.login, name="login"),path("logout/", login.logout, name="logout"),# 生成验证码功能的路由path("image/code/", login.image_code, name="image_code")
]

然后我们回到login.py文件, 在上次写的login函数里面的表单验证那边, 写上验证码的判断, 就是上次写的账号密码登录的判断的那个地方。

在这里插入图片描述

我们在自定义的form类里面加上验证码的输入框:

class LoginForm(forms.Form):username = forms.CharField(label="用户名", widget=forms.TextInput(attrs={"placeholder": "用户名", "autocomplete": "off"}))password = forms.CharField(label="密码", widget=forms.PasswordInput(attrs={"placeholder": "密码", "autocomplete": "off", "type": "password"}))# 验证码输入框code = forms.CharField(label="验证码", widget=forms.TextInput(attrs={"placeholder": "验证码", "autocomplete": "off"}))# 对密码进行校验, 在校验函数里面, 我们对密码进行加密处理def clean_password(self):password = self.cleaned_data['password']return pwd_data.md5(password)

然后再login函数写关于验证码判断的逻辑:

def login(request):if request.method == 'GET':form = LoginForm()return render(request, "login/login.html", {'form': form})form = LoginForm(request.POST)if form.is_valid():# 验证码校验(这一篇文章写的)# 用户输入的验证码user_input_code = form.cleaned_data.pop("code")# 图片生成的验证码code = str(request.session.get("image_code"))# 如果验证码不一致(由于验证码不区分大小写, 所以两边都加了upper函数, 或者都加上lower函数也可以)if user_input_code.upper() != code.upper():# 添加报错信息form.add_error("code", "验证码错误")return render(request, "login/login.html", {'form': form})print(form.cleaned_data)# 登录校验(上一篇文章写的)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*1)return redirect('/')render(request, "login/login.html", {'form': form})

然后我们不要忘记在中间件里面, 把我们写好的生成验证码的路由(“/image/code/”)添加到判断里面:

auth.py:

from django.shortcuts import render, redirect, HttpResponse
from django.utils.deprecation import MiddlewareMixin
from django.conf import settingsclass AuthMiddleware(MiddlewareMixin):# 登录校验def process_request(self, request):# 避免打开login页面之后验证login页面, 不然就会产生死循环。# 这里需要忽略以下路由# 这里千万不要忘记写"/image/code/"if request.path_info in ["/login/", "/logout/", "/image/code/"]:returninfo_dict = request.session.get('info')if info_dict:request.unicom_id = info_dict['id']request.unicom_username = info_dict['username']request.unicom_role = info_dict['role']returnreturn redirect("/login/")def process_view(self, request, view_func, args, kwargs):# 这里千万不要忘记写"/image/code/"if request.path_info in ["/login/", "/logout/", "/image/code/"]:returnrole = request.unicom_roleuser_permission_list = settings.UNICOM_PERMISSION[role]# 当前请求的路由name不在这个列表当中if request.resolver_match.url_name not in user_permission_list:returnreturn HttpResponse("没有权限")

最后我们在前端加上验证码的输入框:

login.html:

<div class="item">{# 验证码输入框 #}{{ form.code }}{# 验证码报错信息展示(无报错就不会展示) #}<span style="color: red">{{ form.code.errors.0 }}</span>{# 验证码展示区域, 把它放在右边 #}<button style="border: none; float: right">{# 验证码图片的生成(src里面是生成验证码的路由, 刚在我们已经配置好了) #}<img src="/image/code/"></button>
</div>

运行结果:

在这里插入图片描述

我们随便登录一个账号试一试:

在这里插入图片描述

验证码是CC2F, 但是输入框里面是CCs2, 那就会有错误信息:

在这里插入图片描述

有验证码错误的报错信息,

并且会自动重新生成一个验证码。

当我们输入正确的验证码的时候:

在这里插入图片描述

再点击登录, 会跳转到首页。(这个验证码错误不需要管它, 重新输入验证码的时候, 那个文字不会消失, 输入正确的验证码之后, 页面就会自动跳转到首页)。

不过有个前提, 就是账号密码必须要正确的情况下才能登录成功, 所以是账号密码要正确, 验证码也要正确。

在这里插入图片描述

登录成功!!!

三、代码展示集合

前端:

login.html:

<!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;}a {text-decoration: none;}input,button {background: transparent;border: 0;outline: none;}body {height: 100vh;background: linear-gradient(#141e30, #243b55);display: flex;justify-content: center;align-items: center;font-size: 16px;color: #03e9f4;}.loginBox {width: 400px;height: 464px;background-color: #0c1622;margin: 100px auto;border-radius: 10px;box-shadow: 0 15px 25px 0 rgba(0, 0, 0, .6);padding: 40px;box-sizing: border-box;}h2 {text-align: center;color: aliceblue;margin-bottom: 30px;font-family: 'Courier New', Courier, monospace;}.item {height: 45px;border-bottom: 1px solid #fff;margin-bottom: 40px;position: relative;}.item input {width: 100%;height: 100%;color: #fff;padding-top: 20px;box-sizing: border-box;}.item input:focus+label,.item input:valid+label {top: 0px;font-size: 2px;}.item label {position: absolute;left: 0;top: 12px;transition: all 0.5s linear;}.btn {padding: 10px 20px;margin-top: 30px;color: #03e9f4;position: relative;overflow: hidden;text-transform: uppercase;letter-spacing: 2px;left: 35%;}.btn:hover {border-radius: 5px;color: #fff;background: #03e9f4;box-shadow: 0 0 5px 0 #03e9f4,0 0 25px 0 #03e9f4,0 0 50px 0 #03e9f4,0 0 100px 0 #03e9f4;transition: all 1s linear;}.btn>span {position: absolute;}.btn>span:nth-child(1) {width: 100%;height: 2px;background: -webkit-linear-gradient(to left, transparent, #03e9f4);left: -100%;top: 0px;animation: line1 1s linear infinite;}@keyframes line1 {50%,100% {left: 100%;}}.btn>span:nth-child(2) {width: 2px;height: 100%;background: -webkit-linear-gradient(to top, transparent, #03e9f4);right: 0px;top: -100%;animation: line2 1s 0.25s linear infinite;}@keyframes line2 {50%,100% {top: 100%;}}.btn>span:nth-child(3) {width: 100%;height: 2px;background: -webkit-linear-gradient(to left, #03e9f4, transparent);left: 100%;bottom: 0px;animation: line3 1s 0.75s linear infinite;}@keyframes line3 {50%,100% {left: -100%;}}.btn>span:nth-child(4) {width: 2px;height: 100%;background: -webkit-linear-gradient(to top, transparent, #03e9f4);left: 0px;top: 100%;animation: line4 1s 1s linear infinite;}@keyframes line4 {50%,100% {top: -100%;}}</style>
</head><body><div class="loginBox"><h2>登录界面</h2><form method="post">{% csrf_token %}<div class="item">{{ form.username }}</div><div class="item">{{ form.password }}<span style="color: red">{{ form.password.errors.0 }}</span></div><div class="item">{{ form.code }}<span style="color: red">{{ form.code.errors.0 }}</span><button style="border: none; float: right"><img src="/image/code/"></button></div><button class="btn">登录<span></span><span></span><span></span><span></span></button></form></div>
</body>
</html>
后端:

code.py:

from PIL import Image, ImageDraw, ImageFont
from random import randint, choicedef create_image_content():# 创建画布# mode='RGB'代表使用RGB, size代表画布大小, color代表颜色, 用的rgb颜色。image = Image.new(mode='RGB', size=(110, 40), color=(255, 255, 255))# 创建画笔draw = ImageDraw.Draw(image, mode='RGB')font = ImageFont.truetype('simhei.ttf', size=30)text = "ABCDEFG123456"image_text = ""for i in range(4):image_text += choice(text)x = 17for 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, fill=f"rgb({R}, {G}, {B})", font=font)x += 20for i in range(1, randint(4, 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)image.save('code.png')# 返回画布(图片)和验证码图片里面的内容return [image, image_text]create_image_content()

login.py:

from django.core.exceptions import ValidationError
from django.shortcuts import render, redirect, HttpResponsefrom project_one.utils import pwd_data
from project_one.utils.code import create_image_content
from project_one.utils.PageData import PageData
from django import formsfrom project_one import models
from io import BytesIO# Create your views here.
class LoginForm(forms.Form):username = forms.CharField(label="用户名", widget=forms.TextInput(attrs={"placeholder": "用户名", "autocomplete": "off"}))password = forms.CharField(label="密码", widget=forms.PasswordInput(attrs={"placeholder": "密码", "autocomplete": "off", "type": "password"}))code = forms.CharField(label="验证码", widget=forms.TextInput(attrs={"placeholder": "验证码", "autocomplete": "off"}))# 对密码进行校验, 在校验函数里面, 我们对密码进行加密处理def clean_password(self):password = self.cleaned_data['password']return pwd_data.md5(password)def login(request):if request.method == 'GET':form = LoginForm()return render(request, "login/login.html", {'form': form})form = LoginForm(request.POST)if form.is_valid():# 验证码校验user_input_code = form.cleaned_data.pop("code")code = str(request.session.get("image_code"))if user_input_code.upper() != code.upper():form.add_error("code", "验证码错误")return render(request, "login/login.html", {'form': form})print(form.cleaned_data)# 登录校验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*1)return redirect('/')render(request, "login/login.html", {'form': form})def logout(request):# 退出登录的时候, 清除session。request.session.clear()return redirect("/login/")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())

urls.py:

"""project_simple URL ConfigurationThe `urlpatterns` list routes URLs to views. For more information please see:https://docs.djangoproject.com/en/4.1/topics/http/urls/
Examples:
Function views1. Add an import:  from my_app import views2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views1. Add an import:  from other_app.views import Home2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf1. Import the include() function: from django.urls import include, path2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from project_one.views import depart, user, assets, admin_role, loginurlpatterns = [# path('admin/', admin.site.urls),path("", depart.index, name="index"),path("depart/", depart.depart, name="depart"),path("depart/add/", depart.add_depart, name="add_depart"),path("depart/<int:nid>/modify/", depart.depart_modify, name="depart_modify"),path("depart/<int:nid>/del/", depart.del_depart, name="del_depart"),path("user/", user.user_info, name="user_info"),path("user/add/", user.user_add, name="user_add"),path("user/<int:nid>/modify/", user.user_modify, name="user_modify"),path("user/<int:nid>/del/", user.user_del, name="user_del"),path("user/add/modelform", user.user_add_modelform, name="user_add_modelform"),path("user/<int:nid>/modify/modelform", user.user_modify_modelform, name="user_modify_modelform"),path("assets_list/", assets.assets, name="assets"),path("assets/add/", assets.assets_add, name="assets_add"),path("assets/<int:nid>/modify/", assets.assets_modify, name="assets_modify"),path("assets/<int:nid>/del/", assets.assets_del, name="assets_del"),path("admin_list/", admin_role.admin, name="admin"),path("admin/add/", admin_role.admin_add, name="admin_add"),path("admin/<int:nid>/modify/", admin_role.admin_modify, name="admin_modify"),path("admin/<int:nid>/reset/pwd/", admin_role.admin_reset_pwd, name="admin_reset_pwd"),path("admin/<int:nid>/del/", admin_role.admin_del, name="admin_del"),path("login/", login.login, name="login"),path("logout/", login.logout, name="logout"),path("image/code/", login.image_code, name="image_code")
]

auth.py:

from django.shortcuts import render, redirect, HttpResponse
from django.utils.deprecation import MiddlewareMixin
from django.conf import settingsclass AuthMiddleware(MiddlewareMixin):# 登录校验def process_request(self, request):# 避免打开login页面之后验证login页面, 不然就会产生死循环。# 这里需要忽略以下路由if request.path_info in ["/login/", "/logout/", "/image/code/"]:returninfo_dict = request.session.get('info')if info_dict:request.unicom_id = info_dict['id']request.unicom_username = info_dict['username']request.unicom_role = info_dict['role']returnreturn redirect("/login/")def process_view(self, request, view_func, args, kwargs):if request.path_info in ["/login/", "/logout/", "/image/code/"]:returnrole = request.unicom_roleuser_permission_list = settings.UNICOM_PERMISSION[role]# 当前请求的路由name不在这个列表当中if request.resolver_match.url_name not in user_permission_list:returnreturn HttpResponse("没有权限")

好了, 这篇文章的内容就到此结束了, 内容不多, 难度也不大, 但是不能忽略验证码这个功能, 因为验证码在网页里面很常见。

以上就是Django的账号登录及权限管理的所有内容了, 如果有哪里不懂的地方,可以把问题打在评论区, 欢迎大家在评论区交流!!!
如果我有写错的地方, 望大家指正, 也可以联系我, 让我们一起努力, 继续不断的进步.
学习是个漫长的过程, 需要我们不断的去学习并掌握消化知识点, 有不懂或概念模糊不理解的情况下,一定要赶紧的解决问题, 否则问题只会越来越多, 漏洞也就越老越大.
人生路漫漫, 白鹭常相伴!!!

相关文章:

  • HTTPS核心机制拆解
  • [服务器备份教程] Rclone实战:自动备份数据到阿里云OSS/腾讯云COS等对象存储
  • 《Java高并发编程核心:volatile关键字全解析》
  • upload靶场1-5关
  • 微服务项目->在线oj系统(Java版 - 4)
  • Qt开发:QUdpSocket的详解
  • CLIP:论文阅读 -- 视觉模型
  • 遨游科普:三防平板是什么?有什么作用?
  • HDMI 屏幕 电脑HDMI HDMI采集卡的关系
  • 华为鸿蒙电脑发布,企业运营效率可以提高吗?
  • DiffPoint:用扩散模型解锁点云重建的新境界
  • 滑动验证码缺口识别与自动化处理技术解析
  • 【聚类】层次聚类
  • 甘特图工具怎么选?免费/付费项目管理工具对比测评(2025最新版)
  • 【数据结构】AVL树的实现
  • 腾讯云安装halo博客
  • 腾讯云Mysql实现远程链接
  • 腾讯云怎么在游戏云中助力
  • spring中yml配置上下文与tomcat等外部容器不一致问题
  • web常见的攻击方式
  • 花旗回应减员传闻:持续评估人力资源战略,将为受影响的个人提供支持
  • 王毅同德国外长瓦德富尔通电话
  • 永久基本农田竟沦为垃圾场,湖南湘潭回应:全面启动专项整治
  • 这个死亡率第一的“老年病”,正悄悄逼近年轻人
  • 河南发布高温橙警:郑州、洛阳等地最高气温将达40℃以上
  • 哈马斯与以色列在多哈举行新一轮加沙停火谈判