所涉及知识点
- 一次请求伴随多次请求
- PIL
- session存储
- 验证码局部刷新,使用src =+ “?”,不需要使用ajax
- ajax发送验证信息
1 路由配置
# urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
path('index/', views.index),
path('get_validCode_img/', views.get_validCode_img)
]
2 login.html
<!-- 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-lg-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 id="valid_code_img" width="115" height="35" src="/get_validCode_img/" alt="">
</div>
</div>
</div>
<input type="button" class="btn btn-default login_btn" value="submit"><span class="error"></span>
</form>
</div>
</div>
</div>
<script src="/static/js/jquery-3.6.0.min.js"></script>
<script>
// 刷新验证码
$("#valid_code_img").click(function () {
$(this)[0].src+="?"
})
$(".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/"
}
else {
$(".error").text(data.msg).css({"color":"red", "margin-left":"10px"})
setTimeout(function () {
$(".error").text("")
}, 1000)
}
}
})
})
</script>
</body>
</html>
3 validCode.py
validCode.py模块用于生成验证码图片,在相应app(此处是blog)下建立一个utils工具包,并在其下建立一个validCode.py文件
# validCode.py
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):
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
img = Image.new('RGB', (115, 35), color=get_random_color()) # 构建img对象
draw = ImageDraw.Draw(img) # 构建绘画对象
iNkedGod_font = ImageFont.truetype('static/font/iNkedGod.ttf', size=20) # 构建字体对象
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 * 20 + 10, 5), random_char, get_random_color(), font=iNkedGod_font) # 在img上写文字
# 保存验证码
valid_code_str += random_char
# width, height = 115, 35
# for i in range(8): # 画噪线
# x1, y1 = random.randint(0, width), random.randint(0, height)
# x2, y2 = random.randint(0, width), random.randint(0, height)
# draw.line((x1, y1, x2, y2), fill=get_random_color())
#
# for i in range(20):
# draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color()) # 画噪点
# x, y = random.randint(0, width), random.randint(0, height)
# draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color()) # 画噪弧
print("valid_code_str", valid_code_str)
request.session["valid_code_str"] = valid_code_str
"""
1 生成随机字符串asf12dfaf565asdfafd
2 为COOKIE增加一个字段{"sessionID": "asf12dfaf565asdfafd"}
3 在django-session中增加一行
session-key session-data
asf12dfaf565asdfafd {"valid_code_str":"12345"}
"""
f = BytesIO() # 内存字节对象
img.save(f, "png") # 保存到内存
data = f.getvalue() # 从f对象读数据
return data
4 编写login视图函数
# views.py
from django.shortcuts import render, HttpResponse, redirect
from django.http import JsonResponse
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 = request.POST.get("valid_code")
# 自动根据cookie中的sessionID字段从django的session表中查询到相应的session信息,再从相应的session中拿到valid_code_str
valid_code_str = request.session.get("valid_code_str")
print("user", user)
print(valid_code, valid_code_str)
if valid_code.upper() == valid_code_str.upper(): # 使用upper()使得验证码不区分大小写
# authenticate去auth_user查询记录,查询成功返回用户对象,查询失败返回None
user = auth.authenticate(username=user, password=pwd)
if user:
# 保存用户状态信息(保存到session中)
# 等价于request.session['key'] = User_obj
# 执行该方法后,就可以通过request.user来获取当前登陆的用户对象
auth.login(request, user)
response["user"] = user.username
else:
response["msg"] = "用户名或者密码错误"
else:
response["msg"] = "验证码错误"
return JsonResponse(response)
return render(request, 'login.html')
def index(request):
return render(request, "index.html")
def get_validCode_img(request):
"""
生成验证码
:param request:
:return:
"""
from blog.utils.validCode import get_valid_code_img
data = get_valid_code_img(request)
return HttpResponse(data)
5 总结
后端任务:接受前端发送来的登录者的登录信息,验证通过将用户状态保存进session并向前端返回登录成功的信息;验证不通过向前端返回具体的错误信息。
前端任务:通过ajax向后端发送登录者的登录信息,并接受相应的响应信息。若是成功信息直接跳转到首页;若是失败信息需将失败信息渲染到页面以提醒登录者。