前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Django教程第3章 | Web开发实战-登录

Django教程第3章 | Web开发实战-登录

作者头像
仲君Johnny
发布2024-01-24 10:48:38
1560
发布2024-01-24 10:48:38
举报

前言

目标:实现用户登录和验证码功能。

知识点:表单验证、错误提示、DjangoAuth统一认证、验证码

效果图

cb21cf97a3a34d4ea25d63481f7c872e.png
cb21cf97a3a34d4ea25d63481f7c872e.png
00c6160fa2024a4eb2baa93976b059c5.png
00c6160fa2024a4eb2baa93976b059c5.png
代码语言:javascript
复制

Django cookie 与 session

Cookie 是存储在客户端计算机上的文本文件,并保留了各种跟踪信息。

识别返回用户包括三个步骤:

  • 服务器脚本向浏览器发送一组 Cookie。例如:姓名、年龄或识别号码等。
  • 浏览器将这些信息存储在本地计算机上,以备将来使用。
  • 当下一次浏览器向 Web 服务器发送任何请求时,浏览器会把这些 Cookie 信息发送到服务器,服务器将使用这些信息来识别用户。

HTTP 是一种"无状态"协议,这意味着每次客户端检索网页时,客户端打开一个单独的连接到 Web 服务器,服务器会自动不保留之前客户端请求的任何记录。

但是仍然有以下三种方式来维持 Web 客户端和 Web 服务器之间的 session 会话:

Cookies

一个 Web 服务器可以分配一个唯一的 session 会话 ID 作为每个 Web 客户端的 cookie,对于客户端的后续请求可以使用接收到的 cookie 来识别。

在Web开发中,使用 session 来完成会话跟踪,session 底层依赖 Cookie 技术。

7a13e1bac8e3b4206b4164c5a4db3bb3.png
7a13e1bac8e3b4206b4164c5a4db3bb3.png
1bd596eae1fe43b1b4e9763c7698041a.png
1bd596eae1fe43b1b4e9763c7698041a.png

代码案例

1.编写模板HTML

代码语言:javascript
复制
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户管理系统</title>
    <link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.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>
</head>
<body>
<div class="account">
    <h2>用户登录</h2>
    <form method="post" novalidate>
        {% csrf_token %}
        <div class="form-group">
            <label>用户名</label>
            {{ form.username }}
            <span style="color: red;">{{ form.username.errors.0 }}</span>
        </div>
        <div class="form-group">
            <label>密码</label>
            {{ form.password }}
            <span style="color: red;">{{ form.password.errors.0 }}</span>
        </div>
        <div class="form-group">
            <label for="id_code">图片验证码</label>
            <div class="row">
                <div class="col-xs-7">
                    {{ form.code }}
                    <span style="color: red;">{{ form.code.errors.0 }}</span>
                </div>
                <div class="col-xs-5">
                    <img id="image_code" src="/image/code/" onclick="changeImg(this)" style="width: 125px;" />
                </div>
            </div>
        </div>
        <input type="submit" value="登 录" class="btn btn-primary">
    </form>
</div>
</body>
<script>
    function changeImg(ths) {
        // 硬编码
        ths.src = '/image/code/?temp=' + Math.random();
    }
</script>
</html>

2.编写模型

代码语言:javascript
复制
from django.db import models


class UserInfo(models.Model):
    username = models.CharField(verbose_name='用户名', max_length=32)
    password = models.CharField(verbose_name='密码', max_length=64)
    age = models.IntegerField(verbose_name='年龄')
    salary = models.DecimalField(verbose_name='工资', max_digits=10, decimal_places=2)
    gender_choices =(
        (1, '男'),
        (2, '女')
    )
    gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices)
    create_time = models.DateTimeField(verbose_name='创建时间')

    # dept_id = models.ForeignKey(to=Department, to_field='id', null=True, blank=True, on_delete=models.SET_NULL)
    dept = models.ForeignKey(verbose_name="部门", to='Department', to_field="id", on_delete=models.CASCADE)

3.编写视图函数

login函数:校验验证码--》验证用户名密码是否正确--》设置用户过期时间为30分钟--》跳转到首页

101a77a61d2af0c03d334c36bf6ff782.png
101a77a61d2af0c03d334c36bf6ff782.png

登录逻辑图

image_code函数:调用check_code(),生成验证码,设置session60过期。

logout函数:退出登录,删除服务器存储的session并跳转到登陆页面。

views.py

代码语言:javascript
复制
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():
        # 验证码的校验
        user_input_code = form.cleaned_data.pop('code')
        code = request.session.get('image_code', "")
        if code.upper() != user_input_code.upper():
            form.add_error("code", "验证码错误")
            return render(request, 'login.html', {'form': form})

        # 查询数据库匹配用户名密码是否正确
        user_obj = models.UserInfo.objects.filter(**form.cleaned_data).first()
        print(user_obj)
        if not user_obj:
            form.add_error('password', '用户名或密码错误')
            return render(request, 'login.html', {'form': form})
        request.session['info'] = {'id': user_obj.id, 'username': user_obj.username}
        # 设置 session 过期时间为30分钟
        request.session.set_expiry(60 * 30)
        return redirect('/user/list/')
    return render(request, 'login.html', {'form': form})


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 logout(request):
    request.session.flush()
    return redirect('/login/')


class LoginForm(BootstrapForm):
    username = forms.CharField(
        label="用户名",
        widget=forms.TextInput,
        required=True
    )
    password = forms.CharField(
        label="密码",
        widget=forms.PasswordInput(render_value=True),
        required=True,
    )
    code = forms.CharField(
        label="验证码",
        widget=forms.TextInput,
        required=True
    )

4.编写统一过滤(AuthMiddleware)

1.排除那些不需要登录就能访问的页面,例如:login请求,验证码请求

2.读取当前访问的用户的session信息,如果能读到,说明已登陆过,可以访问系统。

3.没有登陆过,也就是在访问系统在浏览器没有用户cookie或者已经失效,则跳转到登陆页面。

代码语言:javascript
复制
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect


class AuthMiddleware(MiddlewareMixin):

    def process_request(self, request):
        # 0.排除那些不需要登录就能访问的页面
        #   request.path_info 获取当前用户请求的URL /login/
        if request.path_info in ["/login/", "/image/code/"]:
            return

        # 1.读取当前访问的用户的session信息,如果能读到,说明已登陆过,就可以继续向后走。
        info_dict = request.session.get("info")
        # print(info_dict)
        if info_dict:
            return

        # 2.没有登录过,重新回到登录页面
        return redirect("/login/")

然后在settings.py配置中间件

代码语言:javascript
复制
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',
    'ums.middleware.auth.AuthMiddleware',    # 新增位置
]

5.配置路由

代码语言:javascript
复制
from django.urls import path
from ums.views import auth


path('user/<int:nid>/edit_user_password/', auth.edit_user_password),
path('login/', auth.login),
path('logout/', auth.logout),
path('image/code/', auth.image_code),

本篇中我使用的是手动绘制验证码,大家可以尝试基于下一章将手动验证码换成自动验证码或者滑动验证码。

如果本文对你有帮助,记得点赞关注,你的支持是我最大的动力!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-01-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 效果图
  • Django cookie 与 session
    • Cookies
    • 代码案例
      • 1.编写模板HTML
        • 2.编写模型
          • 3.编写视图函数
            • 4.编写统一过滤(AuthMiddleware)
              • 5.配置路由
              相关产品与服务
              验证码
              腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档