Django 之 Cookie 和 Session

3. Cookie 和 Session 会话

因为 HTTP 协议是无状态的,每次浏览器请求 request都是无状态的,后台服务器无法识别当前请求与上一次请求及之后请求是否为同一用户。

对于静态网站来说无所谓(所有用户看到的都是一样的),但是动态网站(如:淘宝,登录或非登录状态看到的东西是不一样的),无法识别用户是很致命的。

为了保证被连接的状态,服务器会通过用户浏览器在用户被限定硬盘位置写入一些数据,等下次请求时,需要带上这些数据,服务器根据这些就能识别,这就是 Cookie

3.1 简介

虽然 Cookie 解决了 HTTP 协议无状态的问题,但是因为它是保存在用户本地,也容易被利用对服务器进行恶意攻击,这时出现了 Session。

Session 依赖于 Cookie,但是数据保存在服务端,用户浏览器的 Cookie 只会保存一段非明文的识别信息(好比一把钥匙)。每次请求时,都会带上这段信息,然后与数据库中保存的 Session ID 验证是否一致。

Django 内置了通用 session 框架 'django.contrib.sessions',在项目中任何地方都可以调用,同时它也有多种数据保存方式:

  • 数据库
  • 缓存 catch
  • 文件
  • cookie

但是通常我们都保存在数据库中,类似于以下:

3.2 Session 常用方法

session 封装在 HttpRequest 对象中,以键值对的形式存储,通过 request.session 即可读写。

常用方法:

# 类似字典数据类型的内置方法
keys()
items()
setdefault()
clear()


# 它还有下面的方法:
1. flush()
request.session.flush() 		# 将 session 数据清除,并且 cookie 失效
# 删除当前的会话数据和会话cookie。经常用在用户退出后,删除会话。
    
2. set_test_cookie()
# 设置一个测试cookie,用于探测用户浏览器是否支持cookies。由于cookie的工作机制,你只有在下次用户请求的时候才可以测试。

3. test_cookie_worked()
# 返回True或者False,取决于用户的浏览器是否接受测试cookie。你必须在之前先调用set_test_cookie()方法。

4. delete_test_cookie()
# 删除测试cookie。

5. set_expiry(value)
# 设置cookie的有效期。可以传递不同类型的参数值:
    • 如果值是一个整数,session将在对应的秒数后失效。例如request.session.set_expiry(300) 将在300秒后失效.
    • 如果值是一个datetime或者timedelta对象, 会话将在指定的日期失效
    • 如果为0,在用户关闭浏览器后失效
    • 如果为None,则将使用全局会话失效策略
    失效时间从上一次会话被修改的时刻开始计时。

6. get_expiry_age()
# 返回多少秒后失效的秒数。对于没有自定义失效时间的会话,这等同于SESSION_COOKIE_AGE.
# 这个方法接受2个可选的关键字参数
    • modification:会话的最后修改时间(datetime对象)。默认是当前时间。
    •expiry: 会话失效信息,可以是datetime对象,也可以是intNone

7. get_expiry_date()
# 和上面的方法类似,只是返回的是日期

8. get_expire_at_browser_close()
# 返回True或False,根据用户会话是否是浏览器关闭后就结束。

9. clear_expired()
# 删除已经失效的会话数据。

10. cycle_key()
# 创建一个新的会话秘钥用于保持当前的会话数据。django.contrib.auth.login() 会调用这个方法。

3.3 示例一

使用 Cookie 和 Session 来验证登录用户与非登录用户

  1. 视图函数 views.py
from django.shortcuts import render, redirect
from app.models import User
from functools import wraps


def check_code(f):
    """
    验证登录,验证成功,进入首页,失败则重定向到登录页面
    :param f:
    :return:
    """
    @wraps(f)
    def inner(request, *args, **kwargs):
        if request.session.get('is_login'):
            return f(request, *args, **kwargs)
        else:
            return redirect('login')
    return inner


def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')

        user = User.objects.filter(username=username, password=password)[0]
        # 登录成功
        # 1. 生成特殊的字符串
        # 2. 特殊字符串当成key,在数据库的session表中对应一个session value
        # 3. 在响应中向浏览器写了一个Cookie Cookie的值就是 特殊的字符串
        if user:
            request.session['is_login'] = True
            request.session['user_id'] = user.id
            return redirect('home')     # 重定向到个人主页
    else:
        return render(request, 'login.html')


@check_code         # 相当于 home = check_code(home)
def home(request):
    """个人主页"""
    user_id = request.session.get('user_id')
    # 根据 user_id 去数据库中去查数据
    user_obj = User.objects.filter(id=user_id)[0]
    if user_obj:
        return render(request, 'home.html', {'user_obj': user_obj})
    else:
        return render(request, 'home.html', {'user_obj': '匿名用户'})

用户登录,验证成功,写入 session到数据库中。个人主页根据来查相关个人信息。

登出

def logout(request):
    """登出"""
    # 如果没有登录,即意味着没有登出一说
    if not request.session.get('is_login', None):
        return redirect('login')
    
    # 清除session
    request.session.flush()
    # 或者使用下面的方法
    # del request.session['is_login']
    # del request.session['user_id']
    # del request.session['user_name']
    return redirect('login')
  1. 模板
<!--home.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>个人主页</title>
</head>
<body>
    <h1>个人主页</h1>
    <p>用户名:{{ user_obj.username }}</p>
    <p>密码:{{ user_obj.password }}</p>
    <button><a href="{% url 'logout' %}">登出</a> </button>
</body>
</html>
------------------------------------------------------------------------------------------------------------------------
<!--login.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<h1>登录页面</h1>
<form action="{% url 'login' %}" method="post" novalidate>
    {% csrf_token %}
    <p>
        <label>用户名</label>
        <input type="text" name="username">
    </p>

    <p>
        <label>密码</label>
        <input type="password" name="password">
    </p>

    <input type="submit" value="登录">
</form>
</body>
</html>
  1. 路由
from django.contrib import admin
from django.urls import path
from app import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.home, name='home'),
    path('login/', views.login, name='login'),
    path('logout/', views.logout, name='logout'),
]

3.4 示例二

如果登录则显示个人信息(我的账户、修改密码、登出等),没有登录则显示注册和登录。

  1. 视图函数
def home(request):
    """首页"""
    return render(request, 'home.html')


def login(request):
    """登录"""
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')

        user = User.objects.get(username=username)
        if user.password == password:
            request.session['is_login'] = True
            request.session['user_name'] = user.username
            request.session['user_id'] = user.id
            return redirect('home')

    return render(request, 'login.html')


def logout(request):
    """登出"""
    if not request.session.get('is_login', None):
        return redirect('login')
    request.session.flush()
    return redirect('home')
  1. 首页home.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
    <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body {
            padding-top: 70px;
        }
    </style>
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top">
    <div class="container">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">Hubery_Jun</a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav">
                <li class="active"><a href="#">首页 <span class="sr-only">(current)</span></a></li>
                <li><a href="#">热点</a></li>
            </ul>

            <ul class="nav navbar-nav navbar-right">
                <!--如果登录则显示个人信息-->
                {% if request.session.is_login %}
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                           aria-expanded="false">{{ request.session.user_name }} <span class="caret"></span></a>
                        <ul class="dropdown-menu">
                            <li><a href="#">我的账户</a></li>
                            <li><a href="#">修改密码</a></li>
                            <li><a href="{% url 'logout' %}">登出</a></li>
                        </ul>
                    </li>
                <!--没登录显示注册登录-->
                {% else %}
                    <li><a href="#">注册</a></li>
                    <li><a href="{% url 'login' %}">登录</a></li>
                {% endif %}
            </ul>
        </div><!-- /.navbar-collapse -->
    </div><!-- /.container-fluid -->
</nav>


<div class="container">
    <h1>首页</h1>
</div>


<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>

<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
  1. 登录 login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<h1>登录页面</h1>
<form action="{% url 'login' %}" method="post" novalidate>
    {% csrf_token %}
    <p>
        <label>用户名</label>
        <input type="text" name="username">
    </p>

    <p>
        <label>密码</label>
        <input type="password" name="password">
    </p>

    <input type="submit" value="登录">
</form>
</body>
</html>
  1. 路由
from django.contrib import admin
from django.urls import path
from app import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.home, name='home'),
    path('login/', views.login, name='login'),
    path('logout/', views.logout, name='logout'),
]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/2777.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】引用详细解析

目录引用的概念引用的用法引用的特性常引用&#xff08;涉及权限的放大与缩小&#xff09;引用的使用场景**作参数****作返回值**正确使用引用返回传值、传引用效率比较引用和指针的区别引用的概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0…

干货 | 开关电源的PCB布线设计技巧—如何降低EMI?

开关电源PCB排版是开发电源产品中的一个重要过程。许多情况下&#xff0c;一个在纸上设计得非常完美的电源可能在初次调试时无法正常工作&#xff0c;原因是该电源的PCB排版存在着许多问题。为了适应电子产品飞快的更新换代节奏&#xff0c;产品设计工程师更倾向于选择在市场上…

【Zblog建站】搭建属于自己的博客网站,并内网穿透实现公网访问

文章目录1. 前言2. Z-blog网站搭建2.1 XAMPP环境设置2.2 Z-blog安装2.3 Z-blog网页测试2.4 Cpolar安装和注册3. 本地网页发布3.1. Cpolar云端设置3.2 Cpolar本地设置4. 公网访问测试5. 结语1. 前言 想要成为一个合格的技术宅或程序员&#xff0c;自己搭建网站制作网页是绕不开…

第十四届蓝桥杯三月真题刷题训练——第 20 天

目录 第 1 题&#xff1a;纸张尺寸 问题描述 输入格式 输出格式 样例输入1 样例输出1 样例输入 2 样例输出 2 运行限制 代码&#xff1a; 解析&#xff1a; 第 2 题&#xff1a;最大数字 第 3 题&#xff1a;全排列的价值_递推公式 问题描述 输入格式 输出格式…

【中级软件设计师】—操作系统考点总结篇(二)

【中级软件设计师】—操作系统考点总结篇&#xff08;二&#xff09; 1.操作系统概述 1.1操作系统的功能 1.2 特殊的操作系统 1.3 进程的概念和状态 进程与程序的区别&#xff1a; 进程是程序的一次执行过程&#xff0c;没有程序就没有进程 程序是一个静态的概念&#xff0c;…

flowable-ui

一、介绍 flowable-ui主要用于画流程图,之后再使用flowable整合Spring Boot。Flowable提供了一个web UI应用程序来演示和利用Flowable项目提供的功能。 flowable-ui的官网文档地址为: https://www.flowable.com/open-source/docs/bpmn/ch14-Applications/ 二、安装flowab…

Counterpoint发布颈戴式耳机市场报告,苹果Find My加持不易丢

根据市场调查机构 Counterpoint 公布的 2022 年第 4 季度报告&#xff0c;一加凭借着 20.2% 的市场占有率&#xff0c;成为印度市场最大的颈戴式耳机市场厂商。 一加以 20.2% 的市场占有率领先&#xff0c;boAt 以 16% 的份额位居第二。一加云耳 Z2 已经连续 3 个季度成为印度…

【CodeForces】Codeforces Round 859 (Div. 4) D

嘿嘿嘿&#xff0c;CF虐我千百遍&#xff0c;我待CF如初见&#xff01; &#xff08;doge&#xff09; 目录 题目含义&#xff1a; 前缀和&#xff1a; 代码 &#x1f386;音乐分享&#xff08;点击链接可以听哦&#xff09; A Hundred Miles&#xff08;一百英里&#xff09;…

JDBC——Java数据库连接

文章目录一、数据库工具类二、JDBC—— Java数据库连接三、执行DML语句四、执行DQL语句五、关联查询六、执行预编译SQL语句七、SELECT语句八、练习创建表:student1九、向student1表中插入100条数据十、删除名字为Test20---Test100的学生十一、将student1表中所有test学生的年龄…

基于深度学习的花卉检测与识别系统(YOLOv5清新界面版,Python代码)

摘要&#xff1a;基于深度学习的花卉检测与识别系统用于常见花卉识别计数&#xff0c;智能检测花卉种类并记录和保存结果&#xff0c;对各种花卉检测结果可视化&#xff0c;更加方便准确辨认花卉。本文详细介绍花卉检测与识别系统&#xff0c;在介绍算法原理的同时&#xff0c;…

在不丢失数据的情况下解锁锁定的 Android 手机的 4 种方法

尽管您可以使用指纹解锁手机&#xff0c;但大多数智能手机都需要 PIN 码、图案或字母数字代码作为主密码。如果您有一段时间没有输入手机密码&#xff0c;很容易忘记。正是由于这个原因&#xff0c;即使您打开了指纹解锁&#xff0c;大多数智能手机也会让您每天至少输入一次 PI…

Pandas的DataFrame的生产,DF数据查看

这篇文档介绍了 Pandas 的入门使用方法。Pandas 是 Python 的一个数据分析库&#xff0c;可以方便地操作数据和进行数据分析。 本节以下列方式导入 Pandas 与 NumPy&#xff1a; In [1]: import numpy as npIn [2]: import pandas as pd#生成对象 用值列表生成 Seriesopen in…

并发编程(五)-ExecutorService源码分析

一、ExecutorService是什么?ExecutorService 是 Java 中的一个接口&#xff0c;它扩展了 Executor 接口&#xff0c;并提供了更多的方法来处理多线程任务。它是 Java 中用于执行多线程任务的框架之一&#xff0c;可以创建一个线程池&#xff0c;将多个任务提交到线程池中执行。…

【C++进阶】十一、哈希的应用---布隆过滤器(二)

目录 一、布隆过滤器提出 二、布隆过滤器概念 三、布隆过滤器实现 3.1 布隆过滤器的插入 3.2 布隆过滤器的查找 3.3 布隆过滤器的删除 3.4 完整代码 四、布隆过滤器优点 五、布隆过滤器缺陷 一、布隆过滤器提出 在注册账号设置昵称的时候&#xff0c;有些软件要求每个…

元宇宙、区块链 通俗易懂

什么是区块链&#xff1f;比特币挖矿是什么&#xff1f;元宇宙是什么&#xff1f;Web(万维网)的三权化进化&#xff1a;基于此&#xff0c;介绍下“元宇宙”。1992年&#xff0c;美国作家史蒂芬森在《雪崩》一书中首次提出了“元宇宙(Metaverse)”的概念。元宇宙实际上就是一种…

【MIT 6.S081】Lab3: page tables

PgtblPrint a page tableA kernel page table per processSimplify copyin/copyinstr本Lab简单优化了系统的页表功能&#xff0c;使得程序在内核态时可以直接解析用户态的指针。笔者用时约8hPrint a page table 第一部分是为系统添加一个打印给定页表的函数vmprint&#xff0c…

C语言-程序环境和预处理(2)

文章目录预处理详解1.预定义符号2.#define2.1#define定义的标识符2.2#define定义宏2.3#define替换规则注意事项&#xff1a;2.4#和###的作用##的作用2.5带副作用的宏参数2.6宏和函数的对比宏的优势&#xff1a;宏的劣势&#xff1a;宏和函数的一个对比命名约定3.undef4.条件编译…

centos系统/dev/mapper/centos-root目录被占满的解决方式

最近在做虚拟机部署docker微服务时&#xff0c;发现磁盘内存占满&#xff0c;无法进行操作。open /var/lib/dpkg/info/libc6:amd64.templates: no space left on device接下来就写下我在备份虚拟机上如何解决根目录被占满的问题&#xff1a;1、查看虚拟机磁盘使用情况df -h可以…

D - 统计子矩阵 (双指针+前缀和+降维处理)

D - 统计子矩阵 &#xff08;双指针前缀和降维处理&#xff09; 1、问题 D - 统计子矩阵 2、分析 代码 &#xff08;1&#xff09;纯暴力做法&#xff1a; 这个做法就很简单了&#xff0c;我们直接枚举所有的子矩阵&#xff0c;然后在对每一个子矩阵内部的元素逐一累加起…

【计算机二级】综合题目

计算机二级python真题 文章目录计算机二级python真题一、《大学慕课 两问 》二、综合应用题——价值链三、基本操作题 ——信息输出一、《大学慕课 两问 》 附件中的文件data.txt 是教育部爱课程网中国大学MOOC平台的某个 HTML页面源文件,里面包含了我国参与MOOC建设的一批大学…