cookie,Session 机制
- http 无状态短链接:
- 第一次请求 + 第一次响应 断开链接了,不保存信息
- 第二次请求 + 第二次响应 当作全新的请求响应,不带状态
- 响应体(内容)+ 响应头(cookie,…):
- 第一次 id 浏览器请求服务器时,附带发 id 浏览器专属的 cookie 凭证
- 服务器保存每个不同 id 浏览器存储 Session(数据库,redis,文件…)保存 cookie 和 id 信息
- 第二次 id浏览器请求服务器,携带之前的 cookie 凭证
- 服务器校验 cookie,通过则绑定 id 信息
用户登录
form框架
添加session
request.session[‘info’] = lf.cleaned_data
session信息保存在了服务器中的Mysql数据库django_session表中
account.py
# author : Sun; time : 2023/2/9 21:51;
from django.shortcuts import render, redirect
from django import forms
from bm01.utils.encrypt import md5
from bm01 import models
class LoginForm(forms.Form):
username = forms.CharField(
widget=forms.TextInput(attrs={'class': 'form-control'})
)
password = forms.CharField(
widget=forms.PasswordInput(attrs={'class': 'form-control'})
)
def clean_password(self):
return md5(self.cleaned_data['password'])
def login(request):
"""登录"""
if request.method == 'GET':
lf = LoginForm()
return render(request, 'login.html', {'form': lf})
lf = LoginForm(request.POST)
if lf.is_valid():
if models.Admin.objects.filter(**lf.cleaned_data).exists():
admin_object = models.Admin.objects.filter(**lf.cleaned_data).first()
request.session['info'] = {'id': admin_object.id, 'name': admin_object.username}
return redirect("/admin/list/")
lf.add_error("password", "用户名或密码错误")
return render(request, 'login.html', {'form': lf})
return render(request, 'login.html', {'form': lf})
bootstrap form优化
account.py
繁琐
继承时,不能直接继承boootstrapModelForm,得重新写boootstrapForm,然后继承
然鹅 bootstap样式的应用,对应两个来说都是重写init方法于是
BootStrapFormsModelForm中先写bootastrap
然后两个方法在继承它的同时 ,分别继承FormsModel,Form
用到样式时,选择继承BootStrapModelForm还是继承BootStrapForm
比如
中间件
我们需要对每个页面做验证,只有登陆的人才可以访问这些页面
中间件会在视图函数下的每个方法执行前调用,不用在每个方法下面进行判断,不然函数太多,过于繁琐
process_request
process_request有返回值就中止,当前中间件返回(HtttpResponce、render、redirect)
没有返回值继续进行到下一中间件
定义中间件
app目录下新建 middleware/auth.py 文件
# author : Sun; time : 2023/2/10 10:05;
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse, redirect
class M1(MiddlewareMixin):
def process_request(self, request):
print("in")
def process_responce(self, request,responce):
print("in")
return responce
应用中间件
实现登录验证
/auth.py
# author : Sun; time : 2023/2/10 10:05;
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")
print(info_dict)
if info_dict:
return
# 2.如果没有登录信息,会登录页面
return redirect("/login/")
用户注销
urls.py
path('logout/', account.logout),
account.py
def logout(request):
"""登出"""
request.session.clear()
return redirect('/login/')
moban.html上加个链接
再加一个用户名
效果
图片验证码显示
生成验证码参考链接: https://www.cnblogs.com/wupeiqi/articles/5812291.html
报错 原因: 链接ttf文件读取不了,不如直接在电脑Fonts文件里面随便用一个
font, size, index, encoding, layout_engine=layout_engine OSError: cannot open resource [10/Feb/2023 13:43:38] "GET /image/code/ HTTP/1.1" 500 92191
新建文件
code.py
生成验证码
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
# 图片 画笔 操作字体文件
def check_code(width=120, height=30, char_length=5, font_file='BKANT.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__':
# # 1. 直接打开
# img,code = check_code()
# img.show()
# 2. 写入文件
# img,code = check_code()
# with open('code.png','wb') as f:
# img.save(f,format='png')
# 3. 写入内存(Python3)
# from io import BytesIO
# stream = BytesIO()
# img.save(stream, 'png')
# stream.getvalue()
# 4. 写入内存(Python2)
# import StringIO
# stream = StringIO.StringIO()
# img.save(stream, 'png')
# stream.getvalue()
# pass
验证码校验
修改account.py
整个代码
# author : Sun; time : 2023/2/9 21:51;
from django.shortcuts import render, redirect, HttpResponse
from django import forms
from io import BytesIO
from bm01.utils.code import check_code
from bm01.utils.encrypt import md5
from bm01 import models
class LoginForm(forms.Form):
username = forms.CharField(
label="验证码",
widget=forms.TextInput(attrs={'class': 'form-control'})
)
password = forms.CharField(
label="验证码",
widget=forms.PasswordInput(attrs={'class': 'form-control'})
)
code = forms.CharField(
label="验证码",
widget=forms.TextInput(attrs={"class": "form-control"}),
required=True,
)
def clean_password(self):
return md5(self.cleaned_data['password'])
def login(request):
"""登录"""
if request.method == 'GET':
lf = LoginForm()
return render(request, 'login.html', {'form': lf})
lf = LoginForm(request.POST)
if lf.is_valid():
# 获得用户输入的验证码,pop出栈,剩下username,password
user_input_code = lf.cleaned_data.pop('code')
# 获得当前页面生成的验证码
code = request.session.get('image_code',"")
# 进行比较,错误则返回
if code.upper() != user_input_code.upper():
lf.add_error("code", "验证码错误")
return render(request, 'login.html', {'form': lf})
if models.Admin.objects.filter(**lf.cleaned_data).exists():
admin_object = models.Admin.objects.filter(**lf.cleaned_data).first()
request.session['info'] = {'id': admin_object.id, 'name': admin_object.username}
# 登录成功 session保存7天
request.session.set_expiry(60*60*24*7)
return redirect("/admin/list/")
lf.add_error("password", "用户名或密码错误")
return render(request, 'login.html', {'form': lf})
return render(request, 'login.html', {'form': lf})
def logout(request):
"""登出"""
request.session.clear()
return redirect('/login/')
def image_code(request):
""" 生成图片验证码 """
# 调用pillow函数,生成图片
img, code_string = check_code()
# 将图片保存到内存
stream = BytesIO()
img.save(stream, 'png')
# 将验证码的信息保存到session,在login核验
request.session['image_code'] = code_string
# 验证码有校时常600s
request.session.set_expiry(600)
print(code_string)
return HttpResponse(stream.getvalue())
效果
点击图片刷新
<img src="/image/code/" alt="" id="image_code" onclick="this.setAttribute('src','/image/code/?random='+Math.random())">