【三】登录功能实现
【一】登录功能
【路由接口】
-
登陆主接口
login/
-
获取验证码接口
get_code/
【二】需求
- 需要展示的效果
- 用户输入用户名
- 用户输入密码
- 用户输入验证码
- 要求
- 用户名、密码不对时,实时展示提示信息,及必要报错
- 展示动态图像验证码
- 验证码内容构成为 5 位 字母+数字
- 使用到的技术
bootstrap
展示样式ajax
加载点击动作ajax
发送post请求
【三】功能实现 - 前端页面搭建输入数据
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- CDN 链接 引入方法 -->
<!-- Bootstrap 的 CSS 样式文件 -->
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
<!-- Bootstrap 的 JS 文件 (动画效果需要jQuery) -->
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js">// bootstrap </script>
<!-- jQuery 文件 -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"> // jquery</script>
<!-- 以下为 css样式书写区 -->
<style>
</style>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="text-center">登录功能</h1>
<div class="form-group">
<label for="username">用户名</label>
<input type="text" name="username" id="username" class="form-control">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" name="password" id="password" class="form-control">
</div>
<div class="form-group">
<label for="">验证码</label>
<div class="row">
<div class="col-md-6">
<input type="text" name="code" id="id_code" class="form-control">
</div>
<div class="col-md-6">
<img src="/get_code/" alt="" height="38" width='310' id="id_code_img">
</div>
</div>
</div>
<input type="button" class="btn btn-success" value="登陆" id="id_commit">
<span style="color:red;" id="error"></span>
</div>
</div>
</div>
<script>
// 更新验证码图片
$("#id_code_img").click(function () {
// 首先获取标签之前的src
let oldVal = $(this).attr("src");
$(this).attr("src", oldVal += '?')
})
// 绑定按钮事件,提交post请求
$("#id_commit").click(function () {
$.ajax({
url: "",
type: "post",
data: {
"username": $('#username').val(),
"password": $('#password').val(),
"code": $('#id_code').val(),
// 模版语法
"csrfmiddlewaretoken": '{{ csrf_token }}',
},
success: function (args) {
if (args.code === 1000) {
// 跳转到首页
window.location.href = args.url
} else {
// 渲染错误信息
$("#error").text(args.message)
}
}
})
})
</script>
</body>
</html>
【1】前端页面搭建
-
首先是页面搭建
- 页面需要具有的功能
- 输入用户名
- 输入密码
- 输入验证码
- 页面需要具有的功能
<h1 class="text-center">登录功能</h1>
<div class="form-group">
<label for="username">用户名</label>
<input type="text" name="username" id="username" class="form-control">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" name="password" id="password" class="form-control">
</div>
- 动态验证码加载
- 定义一个输入框,用来给用户输入验证码
- 定义一个图片标签,实时展示更新的图片
- tips:
- src属性:
src="/get_code/"
- 在后面跟任意字符可自动刷新请求
- src属性:
- tips:
<div class="form-group">
<label for="">验证码</label>
<div class="row">
<div class="col-md-6">
<input type="text" name="code" id="id_code" class="form-control">
</div>
<div class="col-md-6">
<img src="/get_code/" alt="" height="38" width='310' id="id_code_img">
</div>
</div>
</div>
【2】前端页面事件绑定
(1)点击验证码图片更新验证码
// 更新验证码图片
$("#id_code_img").click(function () {
// 首先获取标签之前的src
let oldVal = $(this).attr("src");
$(this).attr("src", oldVal += '?')
})
- 找到展示图片的图片标签
$("#id_code_img").click(function () {})
- 绑定点击事件
- 获取标签
let oldVal = $(this).attr("src");
- 绑定属性
$(this).attr("src", oldVal += '?')
- 每次点击按钮触发事件,在路由尾部添加任意字符,二次访问后端的生成图片验证码接口,返回验证码
- 获取标签
(2)给按钮绑定点击事件,发送Ajax请求
// 绑定按钮事件,提交post请求
$("#id_commit").click(function () {
$.ajax({
url: "",
type: "post",
data: {
"username": $('#username').val(),
"password": $('#password').val(),
"code": $('#id_code').val(),
// 模版语法
"csrfmiddlewaretoken": '{{ csrf_token }}',
},
success: function (args) {
if (args.code === 1000) {
// 跳转到首页
window.location.href = args.url
} else {
// 渲染错误信息
$("#error").text(args.message)
}
}
})
})
-
找到按钮并绑定事件
$("#id_commit").click(function () {})
-
绑定Ajax事件
$.ajax({})
-
向当前url发送数据
url: ""
-
请求方式是post
type: "post"
-
需要传的数据
-
通过id值拿到输入框输入的值
$('#username').val()
-
通过id值拿到输入框输入的值
"password": $('#password').val()
-
通过id值拿到输入框输入的值
$('#id_code').val()
-
通过模板语法拿到 csrf 校验值
'{{ csrf_token }}'
-
构建数据格式
data: { "username": $('#username').val(), "password": $('#password').val(), "code": $('#id_code').val(), // 模版语法 "csrfmiddlewaretoken": '{{ csrf_token }}', },
-
请求成功或失败,打印提示信息
success: function (args) { if (args.code === 1000) { // 跳转到首页 window.location.href = args.url } else { // 渲染错误信息 $("#error").text(args.message) } }
-
【四】功能实现 - 后端校验数据返回错误信息
【1】返回图片验证码
# 图片相关的模块
# pip install pillow
from PIL import Image, ImageDraw, ImageFont
'''
Image 生成图片
ImageDraw 能够在图片上乱涂乱画
ImageFont 控制字体样式
'''
import random
# 内存管理器模块
from io import BytesIO, StringIO
'''
BytesIO 临时存储数据,返回的数据是二进制数据
StringIO 临时存储数据,返回的数据是字符串数据
'''
# 随机获取 0-255数字
def get_random():
return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
# 获取随机验证码
def get_code(request, *args, **kwargs):
# 方法四:写图片验证码
img_obj = Image.new('RGB', (310, 38), get_random())
# 产生一个画笔对象
img_draw = ImageDraw.Draw(img_obj)
# (字体样式,字体大小)
img_font = ImageFont.truetype('book/static/font/汉仪秀英体简.ttf', 30)
# 随机验证码 -- 五位数(数字/小写字母/大写字母)
code = ''
for i in range(5):
random_int = str(random.randint(0, 9)) # 0-9之间的整数
random_upper = chr(random.randint(65, 90)) # A-Z之间的字母
random_lower = chr(random.randint(97, 122)) # a-z之间的字母
temp = random.choice([random_int, random_upper, random_lower])
'''
一个个写而不是一次写多个
因为一个个写能够控制每个字体的间隙,生成多个一起写没办法控制间隙
'''
img_draw.text((i * 60 + 20, 4), temp, get_random(), img_font)
# 拼接随机字符串
code += temp
print(code)
# 随机验证码在登录的视图函数中需要比对,所以需要找地方存起来,便于其他函数调用
request.session['code'] = code
io_obj = BytesIO()
img_obj.save(io_obj, 'png')
data = io_obj.getvalue()
return HttpResponse(data)
【2】登陆校验逻辑
# 登陆接口
def login(request, *args, **kwargs):
if request.method == 'POST':
back_dict = {"code": 1000, "message": ""}
username = request.POST.get('username')
password = request.POST.get('password')
code = request.POST.get('code')
# (1) 校验验证码是否一致
if request.session.get('code').upper() == code.upper():
# (2)校验用户名和密码是否一致
user_obj = auth.authenticate(request, username=username, password=password)
if user_obj:
# (3) 保存用户状态
auth.login(request, user_obj)
back_dict["url"] = "/home/"
else:
back_dict['code'] = 2000
back_dict["message"] = "用户名或密码错误"
else:
back_dict['code'] = 2000
back_dict["message"] = "验证码错误"
return JsonResponse(back_dict)
return render(request, 'login.html', locals())
-
视图主逻辑
-
校验当前请求方式,限制数据请求输入方式
if request.method == 'POST':
-
构建基础返回数据字典格式
back_dict = {"code": 1000, "message": ""}
-
取到前端输入的用户名/密码/验证码
username = request.POST.get('username')
password = request.POST.get('password')
code = request.POST.get('code')
-
校验验证码是否一致(可选不区分大小写/区分大小写)
if request.session.get('code').upper() == code.upper():
-
校验验证码失败
- 更改状态码
back_dict['code'] = 2000
- 更改提示信息
back_dict["message"] = "验证码错误"
-
校验验证码成功往下走
-
校验两次密码是否一致
-
利用auth模块自带的校验方法
auth.authenticate
是一个 Django 框架中的函数,用于对用户进行身份验证。- 在Django中,身份验证是通过检查用户提供的凭据(例如用户名和密码)来确认用户的身份。
- 当你的应用程序涉及到需要验证用户身份的操作时
- 你可以使用
auth.authenticate
函数来验证用户是否为有效用户。 - 该函数接收两个参数:
request
对象和可选的username
和password
参数。
- 你可以使用
auth.authenticate
- 在验证成功时返回用户对象
- 如果验证失败则返回
None
。
- 这个函数主要用于登录过程以及其他需要验证身份的场景。
- 一旦用户被认证,你可以将其存储在会话中、分配权限或进行其他相关操作。
- 下面是一个使用
auth.authenticate
的示例:
from django.contrib import auth def login(request): if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] user = auth.authenticate(request, username=username, password=password) if user is not None: # 身份验证成功 auth.login(request, user) # 执行其他操作 else: # 身份验证失败 # 执行其他操作或返回错误信息
- 以上的代码演示了从请求中获取用户名和密码,并使用
auth.authenticate
对其进行身份验证。- 如果验证成功,则可以执行其他操作;
- 否则,你可以返回错误消息或执行其他相应的操作。
- 需要注意的是,
auth.authenticate
函数- 只是验证用户的身份
- 而不会创建会话或进行其他跟踪操作。
- 要完整地实现用户登录功能,通常还需要使用
auth.login
函数来创建会话并将用户标记为已登录状态。
-
user_obj = auth.authenticate(request, username=username, password=password)
-
-
校验成功则保存用户状态
- 使用auth模块自带的方法
auth.login(request, user_obj)
- 成功后,定义下一个跳转页面,跳转到首页
back_dict["url"] = "/home/"
-
校验失败
- 更改状态码
back_dict['code'] = 2000
- 更改报错信息
back_dict["message"] = "用户名或密码错误"
-
将信息返回至前端页面展示
return JsonResponse(back_dict)
-
-
返回登录页面,及逻辑函数名称空间
return render(request, 'login.html', locals())
本文来自博客园,作者:Chimengmeng,转载请注明原文链接:https://www.cnblogs.com/dream-ze/p/17571578.html