账户登录
登录界面
修改myproject/employee_management/templates/layout.html
{% block css %}
<style>
.navbar {
border-radius: 0;
}
</style>
{% endblock %}
新建myproject/employee_management/templates/login.html
{% extends 'layout.html' %}
{% block css %}
<style>
.account {
width: 400px;
border: 1px solid #dddddd;
border-radius: 5px;
box-shadow: 5px 5px 20px #aaa;
margin-left: auto;
margin-right: auto;
margin-top: 100px;
padding: 20px 40px;
}
.account h2 {
margin-top: 10px;
text-align: center;
}
</style>
{% endblock %}
{% block content %}
<div class="account">
<h2>用户登录</h2>
<div class="panel-body">
<form method="post">
{% csrf_token %}
<div class="form-group">
<label>用户名</label>
<input type="text" class="form-control" placeholder="用户名" name="username">
</div>
<div class="form-group">
<label>密码</label>
<input type="password" class="form-control" placeholder="密码" name="password">
</div>
<button type="submit" class="btn btn-primary center-block" style="width: 80px;">登录</button>
</form>
</div>
</div>
{% endblock %}
修改myproject/myproject/urls.py
# 登录
path('login/', account.login),
新建myproject/employee_management/views/account.py
from django.shortcuts import render
def login(request):
"""登录"""
return render(request, 'login.html')
浏览器简单访问
用户名密码验证
修改myproject/employee_management/templates/login.html
{% extends 'layout.html' %}
{% block css %}
<style>
.account {
width: 400px;
border: 1px solid #dddddd;
border-radius: 5px;
box-shadow: 5px 5px 20px #aaa;
margin-left: auto;
margin-right: auto;
margin-top: 100px;
padding: 20px 40px;
}
.account h2 {
margin-top: 10px;
text-align: center;
}
</style>
{% endblock %}
{% block content %}
<div class="account">
<h2>用户登录</h2>
<div class="panel-body">
<form method="post" novalidate>
{% csrf_token %}
<div class="form-group">
<label>用户名</label>
{{ form.username }}
<span style="color: red;">{{ form.errors.username.0 }}</span>
</div>
<div class="form-group">
<label>密码</label>
{{ form.password }}
<span style="color: red;">{{ form.errors.password.0 }}</span>
</div>
<button type="submit" class="btn btn-primary center-block" style="width: 80px;">登录</button>
</form>
</div>
</div>
{% endblock %}
修改myproject/employee_management/views/account.py
from django.shortcuts import render, HttpResponse
from django import forms
from employee_management.utils.modelform import BootStrapForm
from employee_management.utils.encrypt import md5
from employee_management.models import Admin
# 这一次不使用ModelForm,使用Form来实现
class LoginForm(BootStrapForm):
username = forms.CharField(
label="用户名",
widget=forms.TextInput(attrs={"class": "form-control"}),
required=True,
)
password = forms.CharField(
label="用户名",
# render_value=True 表示当提交后,如果密码输入错误,不会自动清空密码输入框的内容
widget=forms.PasswordInput(attrs={"class": "form-control"}, ),
required=True,
)
def clean_password(self):
pwd = self.cleaned_data.get("password")
return md5(pwd)
def login(request):
"""登录"""
if request.method == "GET":
form = LoginForm()
return render(request, 'login.html', {"form": form})
form = LoginForm(data=request.POST)
if form.is_valid():
# 验证成功, 获取到的用户名和密码
# print(form.cleaned_data)
# {'username': '123', 'password': '123'}
# {'username': '456', 'password': '0f54af32f41a5ba8ef3a2d40cd6ccf25'}
# 去数据库校验用户名和密码是否正确
admin_object = Admin.objects.filter(**form.cleaned_data).first()
# 如果数据库中没有查询到数据
if not admin_object:
# 手动抛出错误显示在"password"字段下
form.add_error("password", "用户名或密码错误")
return render(request, 'login.html', {"form": form})
return HttpResponse("登陆成功")
return render(request, 'login.html', {"form": form})
浏览器进行测试
新建用户toker
(必须为后来使用md5加密过密码的用户,不能是明文密码的用户)
输入错误的密码
输入正确的密码
修改myproject/employee_management/views/account.py
def login(request):
"""登录"""
if request.method == "GET":
form = LoginForm()
return render(request, 'login.html', {"form": form})
form = LoginForm(data=request.POST)
if form.is_valid():
# 验证成功, 获取到的用户名和密码
print(form.cleaned_data)
# {'username': '123', 'password': '123'}
# {'username': '456', 'password': '0f54af32f41a5ba8ef3a2d40cd6ccf25'}
# 去数据库校验用户名和密码是否正确
admin_object = Admin.objects.filter(**form.cleaned_data).first()
if not admin_object:
form.add_error("password", "用户名或密码错误")
return render(request, 'login.html', {"form": form})
# 如果用户名密码正确
# 网站生成随机字符创,写到用户浏览器的cookie中,再写入到服务器的session中
request.session["info"] = {'id': admin_object.id, 'name': admin_object.username}
return redirect("/admin/list/")
return render(request, 'login.html', {"form": form})
登录成功后,跳转到管理员列表
界面
session
信息保存在了服务器中的Mysql数据库django_session
表中
mysql> use my_project;
mysql> show tables;
+--------------------------------+
| Tables_in_my_project |
+--------------------------------+
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
| employee_management_admin |
| employee_management_department |
| employee_management_prettynum |
| employee_management_userinfo |
+--------------------------------+
mysql> select * from django_session;
+----------------------------------+-------------------------------------------------------------------------------------------------+----------------------------+
| session_key | session_data | expire_date |
+----------------------------------+-------------------------------------------------------------------------------------------------+----------------------------+
| zkgq26t7hqx3yu6xo04bws856002n5aj | eyJpbmZvIjp7ImlkIjoxMiwibmFtZSI6InRva2VyIn19:1pElim:Tus2mHaJUTNTfzhppuah8N0FVdLXQxyvRk_4n-4fP6g | 2023-01-23 06:33:24.373104 |
+----------------------------------+-------------------------------------------------------------------------------------------------+----------------------------+
当实现了这个功能后,我们需要对每个页面做验证,只有登陆的人才可以访问这些页面,这个功能在下一节的中间件中来实现
中间件实现登录验证
中间件会在视图函数下的每个方法执行前调用,不用在每个方法下面进行判断,不然函数太多,过于繁琐。
新建myproject/employee_management/middleware
目录
在其下新建myproject/employee_management/middleware/auth.py
文件
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse, redirect
class AuthMiddleware(MiddlewareMixin):
def process_request(self, request):
# 0.排除不需要的页面
if request.path_info == "/login/":
return
# 1.读取当前访问的用户的session信息,如果能读到,说明已登录过,就可以继续向后走
info_dict = request.session.get("info")
if info_dict:
return
# 2.如果没有登录信息
return redirect("/login/")
修改myproject/myproject/urls.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'employee_management.middleware.auth.AuthMiddleware',
]
浏览器访问/pretty/list/
进行测试
你会发现只要你没登录过,不管你访问什么页面,都会跳转到login
登录界面
登录校验的功能算是实现了,但是登录的用户目前无法退出,下一节进行介绍
用户注销
小插曲: 我刚才整理代码的时候才发现,我因为之前使用了
datetimepicker
的日期插件,粘贴代码的时候,将我原来css样式给覆盖掉了,其实是我粘贴多了,需要先改一下,不然右上角的按钮无法展开,抱歉抱歉
修改myproject/employee_management/templates/layout.html
,将下面的几行注释掉
配置注销按钮的跳转URL地址
然后保存就可以了
接下来实现注销功能
修改myproject/employee_management/views/account.py
def logout(request):
""" 注销 """
# 清楚当前session
request.session.clear()
return redirect("/login/")
修改myproject/myproject/urls.py
path('logout/', account.logout),
浏览器测试
登录成功后,右上角的用户名还不是目前登录的用户,所以我们还需要再做一次修改
因为在login函数
中request.session
中定义的username字段对应的名称为name
,所以我们可以在前端代码中直接调用
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">{{ request.session.info.name }}<span class="caret"></span></a>
图片验证码
生成验证码参考链接: https://www.cnblogs.com/wupeiqi/articles/5812291.html
下载必要的软件
pip3 install pillow
下载字体
点击这里: 验证码字体下载
新建myproject/employee_management/utils/ttf
目录,将字体放在其下
新建myproject/employee_management/utils/code.py
,编辑验证码生成函数
from PIL import Image, ImageDraw, ImageFilter, ImageFont
import random
def check_code(width=120, height=30, char_length=5, font_file='employee_management/utils/ttf/Monaco.ttf', font_size=28):
code = []
img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
draw = ImageDraw.Draw(img, mode='RGB')
def rndChar():
"""
生成随机字母
:return:
"""
return chr(random.randint(65, 90))
def rndColor():
"""
生成随机颜色
:return:
"""
return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))
# 写文字
font = ImageFont.truetype(font_file, font_size)
for i in range(char_length):
char = rndChar()
code.append(char)
h = random.randint(0, 4)
draw.text([i * width / char_length, h], char, font=font, fill=rndColor())
# 写干扰点
for i in range(40):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
# 写干扰圆圈
for i in range(40):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())
# 画干扰线
for i in range(5):
x1 = random.randint(0, width)
y1 = random.randint(0, height)
x2 = random.randint(0, width)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=rndColor())
img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
return img,''.join(code)
if __name__ == '__main__':
img, code_str = check_code()
print(code_str)
with open('code.png', 'wb') as f:
img.save(f, format='png')
修改myproject/employee_management/views/account.py
,引入调用刚刚写的验证码生成函数
from employee_management.utils.code import check_code
from django.shortcuts import HttpResponse
from io import BytesIO
def image_code(request):
""" 生成图片验证码 """
# 调用pillow函数,生成图片
img, code_string = check_code()
# 将图片保存到内存
stream = BytesIO()
img.save(stream, 'png')
return HttpResponse(stream.getvalue())
修改myproject/myproject/urls.py
path('image/code/', account.image_code),
还需要将该函数的URL加入访问白名单,使验证码链接可用
编辑myproject/employee_management/middleware/auth.py
# 0.排除不需要的页面
if request.path_info in ["/login/", "/image/code/"]:
return
修改myproject/employee_management/templates/login.html
{% extends 'layout.html' %}
{% block css %}
<style>
.account {
width: 400px;
border: 1px solid #dddddd;
border-radius: 5px;
box-shadow: 5px 5px 20px #aaa;
margin-left: auto;
margin-right: auto;
margin-top: 100px;
padding: 20px 40px;
}
.account h2 {
margin-top: 10px;
text-align: center;
}
</style>
{% endblock %}
{% block content %}
<div class="account">
<h2>用户登录</h2>
<div class="panel-body">
<form method="post" novalidate>
{% csrf_token %}
<div class="form-group">
<label>用户名</label>
{{ form.username }}
<span style="color: red;">{{ form.errors.username.0 }}</span>
</div>
<div class="form-group">
<label>密码</label>
{{ form.password }}
<span style="color: red;">{{ form.errors.password.0 }}</span>
</div>
<div class="form-group">
<label for="id_code">图片验证码</label>
<div class="row">
<div class="col-xs-7">
<input type="text" name="code" class="form-control" placeholder="请输入图片验证码" required="" id="id_code">
<span style="color: red;"></span>
</div>
<div class="col-xs-5">
<img src="/image/code/" alt="" id="image_code">
</div>
</div>
</div>
<button type="submit" class="btn btn-primary center-block" style="width: 80px;">登 录</button>
</form>
</div>
</div>
{% endblock %}
浏览器访问
验证码的校验
接下来需要验证用户输入的验证码与生成的验证码是否一致
修改myproject/employee_management/views/account.py
- 第一处
code = forms.CharField(
label="验证码",
widget=forms.TextInput(attrs={"class": "form-control"}),
required=True,
)
- 第二处
def image_code(request):
""" 生成图片验证码 """
# 调用pillow函数,生成图片
img, code_string = check_code()
# 写入到自己的session中,以便于后续获取验证码再进行校验
request.session['image_code'] = code_string
# 给session设置 60s 超时
request.session.set_expiry(60)
stream = BytesIO()
img.save(stream, 'png')
return HttpResponse(stream.getvalue())
- 第三处
def login(request):
"""登录"""
if request.method == "GET":
form = LoginForm()
return render(request, 'login.html', {"form": form})
form = LoginForm(data=request.POST)
if form.is_valid():
# 验证成功, 获取到的用户名和密码
print(form.cleaned_data)
# {'username': '123', 'password': '123'}
# {'username': '456', 'password': '0f54af32f41a5ba8ef3a2d40cd6ccf25'}
# 验证码的校验
user_input_code = form.cleaned_data.pop('code')
image_code = request.session.get('image_code', "")
print("user_input_code={}, image_code={}".format(user_input_code, image_code))
if image_code.upper() != user_input_code.upper():
form.add_error("code", "验证码错误")
return render(request, 'login.html', {"form": form})
# 去数据库校验用户名和密码是否正确
admin_object = Admin.objects.filter(**form.cleaned_data).first()
if not admin_object:
form.add_error("password", "用户名或密码错误")
return render(request, 'login.html', {"form": form})
# 如果用户名密码和验证码正确
# 网站生成随机字符创,写到用户浏览器的cookie中,再写入到服务器的session中
request.session["info"] = {'id': admin_object.id, 'name': admin_object.username}
# 重新设置session的超时时间,因为之前设置的session的超时时间的 60s
request.session.set_expiry(60 * 60 * 24)
return redirect("/admin/list/")
return render(request, 'login.html', {"form": form})
浏览器登录测试
现在已经可以正常登录,但是还可以进行优化
我们想要点击验证码图片进行刷新验证码,很简单
修改myproject/employee_management/templates/login.html
<img src="/image/code/" alt="" id="image_code" onclick="this.setAttribute('src','/image/code/?random='+Math.random())">
点击验证码图片后,验证码可刷新
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/100697.html