2-功能1:基于用户认证组件和Ajax实现登录验证(图片验证码)
1、登录页面的设计
(1)label标签的id属性
label标签的id属性,点击label标记,相当于点击了input框 bootstarp样式 class="form-group" class="form-control"
(2)此时的验证码先取静态路径
<div class="form-group"> <label for="id_valid_code_str">验证码</label> <div class="row"> <div class="col-md-6"> <input type="text" id="id_valid_code_str" class="form-control"> </div> <div class="col-md-6"> <img src="/blog/get_validCode/" id="id_valid_code_img" width="270" height="35" title="验证码" alt=""> </div> </div> </div>
2、验证码图片的生成
(1)方式1:HttpResponse返回字符串
(2)方式2:引入PIL模块 pip install pillow
from PIL import Image import random def get_random_color(): """生成随机颜色(255,255,255)""" return tuple([random.randint(0, 255) for _ in range(3)]) def get_validCode(request): # 在本地生成一张图片validCode.png img = Image.new("RGB", (270, 35), color=get_random_color()) with open("validCode.png", 'wb') as f: img.save(f, 'png') with open('validCode.png', 'rb') as f: data = f.read() return HttpResponse(data)
(3)方式3:内存处理
from PIL import Image, ImageDraw, ImageFont from io import BytesIO import random def get_random_color(): """生成随机颜色(255,255,255)""" return tuple([random.randint(0, 255) for _ in range(3)]) def get_validCode(request): # 在内存生成一张图片validCode.png img = Image.new('RGB', (210, 35), color=get_random_color()) f = BytesIO() img.save(f, 'png') data = f.getvalue() return HttpResponse(data)
(4)方式4:加入噪点的,字体的
# 方式4:加入噪点的 from PIL import Image, ImageDraw, ImageFont from io import BytesIO import random import string # string字符串 def get_random_color(): return tuple([random.randint(0, 255) for _ in range(3)]) def get_validCode(request): holly_font = ImageFont.truetype('static/font/holly.ttf', size=28) # 字体 img = Image.new('RGB', (210, 35), color=get_random_color()) draw = ImageDraw.Draw(img) # 在img上作画 # draw.text() # 文字 # draw.line() # 线 # draw.point() # 点 # draw数字字母5个 for i in range(5): random_char = random.choice(string.digits + string.ascii_letters) draw.text((i * 40 + 20, 5), random_char, get_random_color(), font=holly_font) # 补充噪点噪音 width, height = 210, 35 for i in range(100): x1 = random.randint(0, width) x2 = random.randint(0, width) y1 = random.randint(0, width) y2 = random.randint(0, width) draw.line((x1, y1, x2, y2), fill=get_random_color()) for i in range(400): draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color()) x = random.randint(0, width) y = random.randint(0, height) draw.arc((x, y, x+4, y+4), 0, 90, fill=get_random_color()) # 内存处理 f = BytesIO() img.save(f, 'png') data = f.getvalue() return HttpResponse(data)
3、验证码的刷新与字符串保存,验证码解耦
(1)刷新
$("#id_valid_code_img") [img#id_valid_code_img] $("#id_valid_code_img")[0] <img src="/blog/get_validCode/" id="id_valid_code_img" width="270" height="35" title="验证码" alt> $("#id_valid_code_img")[0].src "http://127.0.0.1:8000/blog/get_validCode/" $("#id_valid_code_img")[0].src+="?" # 页面刷新 "http://127.0.0.1:8000/blog/get_validCode/?" $("#id_valid_code_img")[0].src+="?" "http://127.0.0.1:8000/blog/get_validCode/??" $("#id_valid_code_img")[0].src+="?" "http://127.0.0.1:8000/blog/get_validCode/???"
模板层 js代码
<script type="text/javascript"> //刷新验证码 $(function () { $("#id_valid_code_img").click(function () { $(this)[0].src+="?" }) }) </script>
(2)保存验证码字符串
(3)多个用户同时访问验证码
全局变量不可取
(4)session存储验证码字符串
(5)验证码解耦
validCode.py
# 方式4:加入噪点的 from PIL import Image, ImageDraw, ImageFont from io import BytesIO import random import string # string字符串 def get_random_color(): return tuple([random.randint(0, 255) for _ in range(3)]) def get_validCode_img(request): holly_font = ImageFont.truetype('static/font/holly.ttf', size=28) # 字体 img = Image.new('RGB', (210, 35), color=get_random_color()) draw = ImageDraw.Draw(img) # 在img上作画 # draw数字字母5个 valid_code_str = "" # 保存验证码字符串 for i in range(5): random_char = random.choice(string.digits + string.ascii_letters) draw.text((i * 40 + 20, 5), random_char, get_random_color(), font=holly_font) valid_code_str += random_char print("valid_code_str", valid_code_str) # 把验证码放入session中 request.session["valid_code_str"] = valid_code_str # 内存处理 f = BytesIO() img.save(f, 'png') data = f.getvalue() return data
views.py视图
from django.shortcuts import render, HttpResponse, redirect from blog.utils.validCode import get_validCode_img # 导入验证码函数 def login(request): return render(request, 'blog/login.html') def get_validCode(request): """ 基于PIL模块动态生成响应状态码图片 :param request: :return: """ data = get_validCode_img(request) return HttpResponse(data)
4、登录验证
(1)ajax流程图
(2)用户认证auth模块,ajax信息response
(3)ajax success成功执行
(4)代码优化:错误信息1s后消失
(5)完整代码
主url
from django.contrib import admin from django.urls import path, re_path, include urlpatterns = [ path('admin/', admin.site.urls), re_path(r'^blog/', include(('blog.urls', 'blog'))) ]
url
from django.urls import path, re_path from blog import views from django.views.static import serve from cnblog import settings urlpatterns = [ re_path('^login/$', views.login, name='login'), re_path('^get_validCode/$', views.get_validCode, name='get_validCode'), re_path('^index/$', views.index, name='index'), ]
view视图
from django.shortcuts import render, HttpResponse, redirect from blog.utils.validCode import get_validCode_img # 导入验证码函数 from django.http import JsonResponse # Json数据返回到前端 from django.contrib import auth # 用户认证组件 def login(request): if request.method == "POST": response = {'user': None, "msg": None} user = request.POST.get("user") pwd = request.POST.get("pwd") valid_code_str = request.POST.get("valid_code_str") _valid_code_str = request.session.get("valid_code_str") # 验证码验证 if valid_code_str.upper() == _valid_code_str.upper(): # 用户认证 user = auth.authenticate(username=user, password=pwd) if user: auth.login(request, user) # request.user == 当前登录对象 response["user"] = user.username else: response["msg"] = "用户名或者密码错误" else: response['msg'] = "验证码错误" return JsonResponse(response) return render(request, 'blog/login.html') def get_validCode(request): """ 基于PIL模块动态生成响应状态码图片 :param request: :return: """ data = get_validCode_img(request) return HttpResponse(data)
def index(request): return HttpResponse(request.user.username)
utils工具包:验证码解耦
# 方式4:加入噪点的 from PIL import Image, ImageDraw, ImageFont from io import BytesIO import random import string # string字符串 def get_random_color(): return tuple([random.randint(0, 255) for _ in range(3)]) def get_validCode_img(request): holly_font = ImageFont.truetype('static/font/holly.ttf', size=28) # 字体 img = Image.new('RGB', (210, 35), color=get_random_color()) draw = ImageDraw.Draw(img) # 在img上作画 # draw数字字母5个 valid_code_str = "" # 保存验证码字符串 for i in range(5): random_char = random.choice(string.digits + string.ascii_letters) draw.text((i * 40 + 20, 5), random_char, get_random_color(), font=holly_font) valid_code_str += random_char print("valid_code_str", valid_code_str) # 把验证码放入session中 request.session["valid_code_str"] = valid_code_str # 内存处理 f = BytesIO() img.save(f, 'png') data = f.getvalue() return data
模板层
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css"> <script src="/static/js/jquery-3.2.1.min.js"></script> </head> <body> <h3>登录页面</h3> <div class="container"> <div class="row"> <div class="col-md-6 col-lg-offset-3"> <form> {% csrf_token %} <div class="form-group"> <label for="id_username">用户名</label> <input type="text" id="id_username" class="form-control"> </div> <div class="form-group"> <label for="id_password">密码</label> <input type="password" id="id_password" class="form-control"> </div> <div class="form-group"> <label for="id_valid_code_str">验证码</label> <div class="row"> <div class="col-md-6"> <input type="text" id="id_valid_code_str" class="form-control"> </div> <div class="col-md-6"> <img src="/blog/get_validCode/" id="id_valid_code_img" width="270" height="35" title="验证码" alt=""> </div> </div> </div> <input type="button" class="btn btn-default login-btn" value="登录"><span class="error"></span> </form> </div> </div> </div> </body> </html>
ajax代码
<script type="text/javascript"> //刷新验证码 $(function () { $("#id_valid_code_img").click(function () { $(this)[0].src += "?" }) }); //登录验证 $(function () { $('.login-btn').click(function () { $.ajax({ url: '', type: 'post', data: { user: $("#id_username").val(), pwd: $("#id_password").val(), valid_code_str: $("#id_valid_code_str").val(), csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val() }, success: function (data) { console.log(data) if (data.user) { location.href = "/blog/index" } else { $('.error').text(data.msg).css({'color': 'red', 'margin-left': '20px'}); //定时器 1s后error_msg 消失 setTimeout(function () { $('.error').text("") }, 1000) } } }) }) }) </script>
(6)滑动验证码:django-demo
(7)总结
总结: 1 一次请求伴随多次请求 2 PIL # 生成验证码图片 3 session存储 # 把验证码放入session中 request.session["valid_code_str"] = valid_code_str 4 验证码刷新 //刷新验证码 $(function () { $("#id_valid_code_img").click(function () { $(this)[0].src += "?" }) });