django web开发 (八) 账户登录

cookie,Session 机制

  • http 无状态短链接:
  1. 第一次请求 + 第一次响应 断开链接了,不保存信息
  2. 第二次请求 + 第二次响应 当作全新的请求响应,不带状态
  • 响应体(内容)+ 响应头(cookie,…):
  1. 第一次 id 浏览器请求服务器时,附带发 id 浏览器专属的 cookie 凭证
  2. 服务器保存每个不同 id 浏览器存储 Session(数据库,redis,文件…)保存 cookie 和 id 信息
  3. 第二次 id浏览器请求服务器,携带之前的 cookie 凭证
  4. 服务器校验 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())">

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值