基于用户认证组件和Ajax实现登录验证(图片验证码)
UserInfo表既有原生auth_user表的字段,又有你扩展的字段,以后用的接口UserInfo既是自己的用户表又是原生认证组件的用户表
一.登录页面的设计
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css"> </head> <body> <h3>登录页面</h3> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3" > <form> {% csrf_token %} <div class="form-group"> <label for="user">用户名</label> <input type="text" id="user" class="form-control"> </div> <div class="form-group"> <label for="pwd">密码</label> <input type="password" id="pwd" class="form-control"> </div> <div class="form-group"> <label for="">验证码</label> <div class="row"> {# 独立一行 #} {# 各占一半 #} <div class="col-md-6"> <input type="text" id = "valid_code" class="form-control"> </div> <div class="col-md-6"> <img width="265" height="38" id="valid_code_img" src="/get_valid_img/" alt=""> </div> </div> </div> <input type="button" class="btn btn-default login_btn " value="submit"><span class="error"></span> <a href="/register/" class="btn btn-success pull-right">注册</a> </form> </div> </div> </div>
二.验证码图片的生成
validCode.py
# -*- coding:utf-8 -*- import random def get_random_color(): # 生成随机颜色三要素 return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) def get_valid_code_img(request): # 方式一:写死了 # with open("kobe.jpg", "rb") as f: # data = f.read() # return HttpResponse(data) # 方式二:磁盘中 速度慢 # pip install pillow # 图像处理模块 # from PIL import Image # img = Image.new("RGB", (265, 38), color=get_random_color()) # Image.new(mode,size,color) 长度265 高度38 # # # 生成随机图片 # with open("validCode.png", "wb") as f: # 先加到磁盘上 # img.save(f, "png") # 会生成一个叫validCode.png的图片 # # # 读出图片 # with open("validCode.png", "rb") as f: # data = f.read() # 方式三:放在内存中 # from PIL import Image # from io import BytesIO # BytesIO就是内存管理 # img = Image.new("RGB", (265, 38), color=get_random_color()) # Image.new(mode,size,color) # # f = BytesIO() # 内存句柄 # img.save(f, "png") # save到内存中 # data = f.getvalue() # 读数据 # 方式四:放在内存中, 添加文字 from PIL import Image, ImageDraw, ImageFont # ImageDraw是画笔,ImageFont是字体大小 from io import BytesIO img = Image.new("RGB", (265, 38), color=get_random_color()) # Image.new(mode,size,color) draw = ImageDraw.Draw(img) # 在img中画东西,draw.text()写文字,draw.line()画线,draw.point()画点 kumo_font = ImageFont.truetype("static/fonts/KumoFont.ttf", size=30) # 参数为字体路径和大小 # global valid_code_str valid_code_str = "" for i in range(6): random_num = str(random.randint(0, 9)) random_low_alpha = chr(random.randint(97, 122)) random_upper_alpha = chr(random.randint(65, 90)) random_char = random.choice([random_num, random_low_alpha, random_upper_alpha]) # text(self, xy, text, fill=None, font=None, anchor=None,*args, **kwargs) # xy:坐标 text:文字 fill:颜色 font:字体 draw.text(((30*i+45), 5), random_char, get_random_color(), font=kumo_font) # 保存验证码字符串 valid_code_str += random_char f = BytesIO() # 内存句柄 img.save(f, "png") data = f.getvalue() # 读数据 return data
噪声噪线
validCode.py
补充躁点躁线, 防止机器 width = 265 # 要跟上边的宽高一致 height = 38 for i in range(10): x1 = random.randint(0, width) x2 = random.randint(0, width) y1 = random.randint(0, height) y2 = random.randint(0, height) draw.line((x1, y1, x2, y2), fill=get_random_color()) for i in range(80): 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())
三.验证码刷新
$("#valid_code_img")[0] <img width="270" height="40" id="valid_code_img" src="http://127.0.0.1:8000/get_validCode_img/??" alt> $("#valid_code_img")[0].src "http://127.0.0.1:8000/get_validCode_img/??" $("#valid_code_img")[0].src+="?" #+="?"添加一次这个就刷新一次验证码 "http://127.0.0.1:8000/get_validCode_img/???" $("#valid_code_img")[0].src+="?" "http://127.0.0.1:8000/get_validCode_img/????" $("#valid_code_img")[0].src+="?" "http://127.0.0.1:8000/get_validCode_img/?????" $("#valid_code_img")[0].src+="?" "http://127.0.0.1:8000/get_validCode_img/??????" $("#valid_code_img")[0].src+="?" "http://127.0.0.1:8000/get_validCode_img/???????"
login.html
<script src="/static/js/jquery-3.3.1.js"></script> <script> {# 刷新验证码,不用ajax也可以 #} $("#valid_code_img").click(function () { $(this)[0].src += "?" }); </script>
四.保存验证码字符串
validCode.py
valid_code_str = "" #保存验证码字符串,这样才能验证 for i in range(5): random_num = str(random.randint(0,9)) random_low_alpha = chr(random.randint(95,122)) random_upper_alpha = chr(random.randint(65,90)) random_char = random.choice([random_num, random_low_alpha, random_upper_alpha]) draw.text((i*50+20, 5), random_char, get_random_color(), font=kumo_font) #保存验证码字符串 valid_code_str += random_char #做一个累加 print("valid_code_str", valid_code_str) request.session["valid_code_str"] = valid_code_str #保存它,写一个session ''' 1 sdajsdq33asdf #生成一个随机字符串, 2 COOKIE {"sessionid":sdajsdq33asdf} #设置一个cookie,返回给cookie那边一个键叫sessionid,值是随机字符串 3 django-session #数据部分保存到了django_session;在session表进行存储 session-key session-data sdajsdq33asdf {"valid_code_str":"12345"} ''' f = BytesIO() img.save(f,"png") data = f.getvalue() return HttpResponse(data)
五.登录验证
#global valid_code_str 这里不能把它变成全局变量,这时虽然校验时可以拿到valid_code_str,但如果是两个人一块访问,那么那个验证码的值存的是最后一个人访问(刷新)的,前面那个人那个就取不到了应该每个人的单独保存,使用会话跟踪技术,把每个人校验的值存到cookie里边
views.py
# -*- encoding:utf-8 -*- from django.shortcuts import render, HttpResponse, redirect import random # Create your views here. from django.http import JsonResponse from django.contrib import auth def login(request): if request.method == "POST": response = {"user": None, "msg": None} # 先构建一个字典,"user":None默认没有登录成功,"msg"里边放错误信息 user = request.POST.get("user") pwd = request.POST.get("pwd") valid_code = request.POST.get("valid_code") # global valid_code_str,不能使用这种方法,因为当多个人同时登录的时候valid_code_str会被覆盖掉,会产生混淆 # 使用会话跟踪技术,session来保存每个人的验证码,request.session["valid_code_str"] = valid_code_str valid_code_str = request.session.get("valid_code_str") if valid_code.upper() == valid_code_str.upper(): # 验证验证码,不区分大小写 # 验证用户名密码 user = auth.authenticate(username=user, password=pwd) # 用户认证组件 if user: # 把这个user注册进去,只要登录成功了,request.user就是当前登录对象用户,否则它就是个匿名对象 auth.login(request, user) # requese.user 当前登录对象,登录成功在这里不能跳转,用的是ajax请求而不是form请求,ajax请求只接收一个数据data response["user"] = user.username else: response["msg"] = "用户名或者密码错误!" else: response["msg"] = "验证码错误!" return JsonResponse(response) # 直接把字典放里面,它帮我们序列化,而且在ajax那边直接拿到对象也不用反序列化 return render(request, 'login.html') def index(request): return render(request, "index.html")
login.html
{# ajax登录验证 #}
$(".login_btn").click(function () {
$.ajax({
url:"",
type:"post",
data:{
user:$("#user").val(), {# 获取用户名输入数据 #}
pwd:$("#pwd").val(), {# 获取密码输入数据 #}
valid_code:$("#valid_code").val(), {# 获取验证码输入数据 #}
csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val() {# 必须加这个键值对才能通过校验 #}
},
success:function (data) {
console.log(data);
if (data.user){ {# 判断有没有值,出错就把错误信息显示在页面上 #}
location.href = "/index/" {# 登录成功就跳转到index页面 #}
}
else {
$(".error").text(data.msg).css({"color": "red", "margin-left":"20px"})
{# 规定时间清空错误信息 #}
setTimeout(function () {
$(".error").text("")
}, 1000)
}
}
})
})
总结:
1 一次请求伴随多次请求
2 PIL
3 session存储
4 验证码刷新
附:
滑动验证码--->引入这样一个插件
要先把social-auth-app-django下载下来
C:UsersAdministrator>pip install social-auth-app-django Collecting social-auth-app-django
把它嵌入到我们的代码里边