快速上手Django(七) -Django之登录cookie和session

news2024/9/23 10:26:50

文章目录

  • 快速上手Django(七) -Django之登录cookie和session
    • 一、cookie、session基础
      • cookie
      • session
    • 二、Django Session
      • Django启用Session
      • Django Session存储方式
    • 三、Django中自定义用户模型
      • 需求背景
      • 自定义用户模型整体实现思路
      • 自定义User模型
        • 示例代码
      • 【非必须】自定义一个管理器BaseUserManager 用于创建用户
    • 四、Django 自定义用户登录认证
      • 需求背景描述
      • django(权限、认证)系统基础
      • 实现思路
    • 五、工作常用总结
      • Django,request.user始终是匿名用户
      • django 判断当前请求用户没有有登录
        • is_authenticate 判断⽤户是否登录
        • Django 通过中间件全局判断用户登录状态
    • 参考

快速上手Django(七) -Django之登录cookie和session

一、cookie、session基础

会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。

cookie

Cookie原理、Set-Cookie常用字段、应用
参考URL: https://blog.csdn.net/jiangshangchunjiezi/article/details/104433135

在这里插入图片描述

Cookie Http 请求头由服务器使用set-Cookie头发送,或者在Javascript中使用document.cookie设置

Set-Cookie Http响应头 用于从服务器向用户代理发送cookie,然后浏览器会将数据设置给下次请求的Cookie请求头,返回服务器。

session

Session是服务端会话技术,依赖于Cookie,如果在浏览器中禁用cookie的话,那么session就失效了,因为它需要浏览器的cookie值去session里做对比。

当用户登陆成功时,会生成一个sessionid保存在cookies中,可以在数据库django_session中查看,当用户访问其他页面时,可以通过sessionid判断用户是否已经登陆。

二、Django Session

Django启用Session

Django默认启用Session,可以在设置文件settings.py

MIDDLEWARE = [
    
    'django.contrib.sessions.middleware.SessionMiddleware',
]

如果禁用session,则注释即可。
禁用的话,如果你用到 request.session,就会报 ‘Request’ object has no attribute ‘session’。

Django Session存储方式

在settings.py文件中,可以设置session数据的存储方式,可以保存在数据库、本地缓存等。
默认是存储在数据库中的。

SESSION_ENGINE='django.contrib.sessions.backends.db'
1. 数据库Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)

2. 缓存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置

3. 文件Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 

4. 缓存+数据库
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎

5. 加密Cookie Session
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎

如果存储在数据库中,则需要安装Session应用,默认已设置:

INSTALLED_APPS = [

    'django.contrib.sessions',
]

在进行数据库迁移的时候,Django自动帮我们生成了django_session表,有3个字段,分别为session_key,session_data,expris_date,Django中session的默认过期时间是14天。

迁移数据库后,就会生成django_session表:

三、Django中自定义用户模型

需求背景

开启一个新项目,官方强烈推荐用户自定义用户模型,即使默认的用户模型目前已经足够,但是未来可能会要扩展。

自定义用户模型整体实现思路

django内置权限系统可以自定义功能扩展。

一般情况下,我们实现自定义用户模型的时候,都会从AbstractUser继承。然后实现我们自定义的用户模型。

整体实现思路:
1) 自定义User模型
2) 在settings.py中设置AUTH_USER_MODEL指向它(这样我们就告诉Django使用我们的自定义模型而不是默认模型。)
3) 数据迁移(一定要先设置好settings后再执行migrate)
4) Django 自定义用户登录认证
自定义UserManager继承django的ModelBackend类,覆写authenticate方法。
settings.py 指定你的UserManager类。

5) 验证通过 调用django的 login方法,完成登录,此时会往django_session表入库一条记录。

# 使用Django的login()函数进行登陆
login(request, user)

自定义User模型

模型MyUser在模型User的基础上新增了上述字段,它继承父类 AbstractUser,而 AbstractUser 是模型 User的父类,因此模型MyUser具有模型User的全部字段。

示例代码

示例代码,具体字段根据项目所需设置

from django.db import models
from django.contrib.auth.models import AbstractUser
 
 
class MyUser(AbstractUser):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField('姓名', max_length=50, default='匿名用户')
    introduce = models.TextField('简介', default='暂无介绍')
    company = models.CharField('公司', max_length=100, default='暂无信息')
    profession = models.CharField('职业', max_length=100, default='暂无信息')
    address = models.CharField('住址', max_length=100, default='暂无信息')
    telephone = models.CharField('电话', max_length=11, default='暂无信息')
    wx = models.CharField('微信', max_length=50, default='暂无信息')
    qq = models.CharField('QQ', max_length=50, default='暂无信息')
    wb = models.CharField('微博', max_length=100, default='暂无信息')
	email = models.EmailField(unique=True, blank=True, null=True, verbose_name='邮箱')
    photo = models.ImageField('头像', blank=True, upload_to='images/user/')
 
    # 设置返回值
    def __str__(self):
        return self.name

继承了类 AbstractUser将 id 由自带的 int 自增改为 uuid
修改,规定邮箱不可重复
新建用户时间给了一个初始值
超级用户默认为 False

(1)settings.py配置如下

AUTH_USER_MODEL = 'account.MyUser' # account为项目应用,MyUser为account的models.py的模型

【非必须】自定义一个管理器BaseUserManager 用于创建用户

django自带User模型,导入方法:from django.contrib.auth.models import User
如果你的User定义了不同的字段, 你就要去自定义一个管理器,它继承自BaseUserManager并提供两个额外的方法:

class UserManager(BaseUserManager):
    use_in_migrations = True
 
    def _create_user(self, username, email, password, **extra_fields):
        """
        使用给定的用户名、电子邮件和密码创建并保存用户。
        """
        # 如果没有username则抛出异常
        if not username:
            raise ValueError('The given username must be set')
        # 标准化电子邮件,查看源码会发现是用@进行分割
        email = self.normalize_email(email)
        # 标准化用户名
        username = self.model.normalize_username(username)
        user = self.model(username=username, email=email, **extra_fields)
        # 为用户设置密码,将纯文本密码转换为用于数据库存储的哈希值
        user.set_password(password)
        # 保存用户
        user.save(using=self._db)
        return user
 
    def create_user(self, username, email=None, password=None, **extra_fields):
        # 设置is_staff默认值为False,is_superuser默认值为False
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(username, email, password, **extra_fields)
 
    def create_superuser(self, username, email, password, **extra_fields):
        # 设置is_staff默认值为True,is_superuser默认值为True
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        
        # 如果调用此方法,is_staff必须为True,否则会抛出异常
        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        # 如果调用此方法,is_superuser必须为True,否则会抛出异常
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')
 
        return self._create_user(username, email, password, **extra_fields)

我们还需要定义自己的UserManager,因为默认的UserManager在创建用户的时候使用的是username和password

个人经验:
但是观察这个方法 其实就是 你的用户模型入库,其实我们也没有必要 自定义BaseUserManager,在登录校验过后,我们直接使用模型自己入库即可。完全没有必要继承BaseUserManager搞一套这个东西,感觉没啥用- -!

四、Django 自定义用户登录认证

Django进阶教程:如何扩展Django用户模型
参考URL: https://zhuanlan.zhihu.com/p/378856858

需求背景描述

有时候 Django 自带的用户登录认证不能满足我们的需求,比如我不想要用户名+密码登录,我想手机号+验证码登录,这样就需要我们去修改 Django 自带的认证了。

django(权限、认证)系统基础

Django的这套权限系统有三个核心,User,Permission,Group
在Web应用中,任何的权限系统要做的第一步就是用户识别,也就是我们常说的登陆(login)。只有正确的登陆校验,知道用户是谁了,才能够知道用户能干什么,那就是许可(Permission)需要负责解决的事情,而Group则是批量设置许可的时候的一个便利手段了。

在view中,我们就可以使用request.user获取当前的登陆用户User对象。如果当前用户没有登陆,那么request.user将会是我们之前所说的AnonymousUser对象。我们可以用User对象的is_authenticated()方法将这两者区分开来:

if request.user.is_authenticated():
    # 做一些事情针对验证用户.
else:
    # 做一些事情对于匿名未登录用户.

那么如何登陆一个用户呢?
需要两个函数:authenticate(username,password)和login(request,user),位于django.contrib.auth模块中;

1.authenticate(username,password)函数需要两个参数username,password,如果校验通过则返回User对象,如果校验不通过返回None
如果认证信息有效,会返回一个 User 对象。authenticate()会在User 对象上设置一个属性来标识后端已经认证了该用户,且该信息在后续的登录过程中是需要的。

2.login接受两个参数,第一个是request对象,第二个是user对象。
login方法使用SessionMiddleware将userID存入session当中。注意,在用户还未登录的时候,也存在着匿名用户的Session,在其登陆之后,之前在匿名Session中保留的信息,都会保留下来。这两个方法要结合使用,而且必须要先调用authenticate(),因为该方法会User的一个属性上纪录该用户已经通过校验了,这个属性会被随后的login过程所使用

当用户登陆成功时,会生成一个sessionid保存在cookies中,可以在数据库django_session中查看,当用户访问其他页面时,可以通过sessionid判断用户是否已经登陆。

实现思路

其实这里有2种大实现方案

【推荐】方案1:
Django 默认使用用户认证的是ModelBackendauthenticate()方法,这个方法就是登录时对用户认证的方法。我们要改的就是这个方法。

思路:继承ModelBackend重写authenticate方法、get_user 方法。
认证后端是一个类,它实现了两个必要的方法get_user(user_id) 和 authenticate(request, **credentials)。

  1. get_user 方法接收一个 user_id ——可以是用户名、电话号码,或者其他唯一标识用户的信息——然后返回一个用户对象或 None。
  2. 覆写authenticate 方法 实现判断是否可以登录

方案2:
不用官方的那一套,但是使用的还是前面的自定义用户模型,我们自己对比,然后入库。
设置set-cookie,然后返回。

五、工作常用总结

Django,request.user始终是匿名用户

Django自定义后端“get_user”从未调用。用户总是匿名的
参考URL: https://www.cnpython.com/qa/230722

如果您使用的是自定义用户模型,那么您基本上都是自己的,而django.contrib.auth框架无法帮助您进行身份验证。

ModelBackend类默认的实现,如下,我们看到他是从UserModel这个模型中获取的数据,而我们是自定义用户模型,所以我们也要覆写这个方法:

def get_user(self, user_id):
    try:
        user = UserModel._default_manager.get(pk=user_id)
    except UserModel.DoesNotExist:
        return None
    return user if self.user_can_authenticate(user) else None

总结,需要确认:

  • 你setting.py 放开了 ‘django.contrib.auth.middleware.AuthenticationMiddleware’,
    我被坑在这里了,你要能调 get_user方法,你就需要开放这个中间件,get_user方法是由这个中间件,在接收到request请求时,调用的。
  • 你覆写了get_user方法。

django 判断当前请求用户没有有登录

is_authenticate 判断⽤户是否登录

Django⽤户认证系统提供了⽅法request.user.is_authenticated()来判断⽤户是否登录。
如果通过登录验证则返回True。反之,返回False。
缺点:登录验证逻辑很多地⽅都需要,所以该代码需要重复编码好多次。

Django 通过中间件全局判断用户登录状态

TODO

参考

一篇文章搞定 Django Cookie 与 Session
参考URL: https://www.toutiao.com/article/6840691101863510531
django自定义用户登录(个人笔记)
参考URL: https://www.bbsmax.com/A/pRdBNbXndn/
自学django中重写User模型(笔记)
参考URL: https://blog.csdn.net/weixin_43972292/article/details/85786380
django中request.user的由来
参考URL: https://zhuanlan.zhihu.com/p/415424659

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kafka 设计原理

文章目录1、Kafka 使用场景2、Kafka 架构2.1、工作流程2.2、副本机制2.3、生产者2.3.1、生产方式2.3.2、分区策略Round-robinRandomnessKey-ordering2.4、消费者2.4.1、消息队列模型2.4.2、消费方式2.4.3、分区策略RangeRoundRobin2.5、消息可靠性1、Kafka 使用场景 Kafka 是采…

图书馆座位预约管理系统毕业设计,图书馆座位管理系统设计与实现,图书馆座位预约系统毕业论文毕设作品参考

项目背景和意义 目的:本课题主要目标是设计并能够实现一个基于web网页的教室图书馆座位预约系统,整个网站项目使用了B/S架构,基于python的Django框架下开发;管理员通过后台录入信息、管理信息,设置网站信息&#xff0c…

CUDA入门和网络加速学习(一)

0. 简介 最近作者希望系统性的去学习一下CUDA加速的相关知识,正好看到深蓝学院有这一门课程。所以这里作者以此课程来作为主线来进行记录分享,方便能给CUDA网络加速学习的萌新们去提供一定的帮助。 1. GPU与CPU区别 处理器指标一般主要分为两大类&…

异构体之间通信

一、WIFI通信 1、网络配置 IP地址 网络地址 主机地址 假设IP地址是192.168.100.1,这个地址中包含了很多含义。如下所示: 网络地址(相当于街道地址):192.168.100.0 主机地址(相当于各户的门号):0.0.0.1 IP地址(相当于住户地址…

【Java进阶篇】第七章 多线程

文章目录一、多线程概述1、进程与线程2、进程与线程的关系二、多线程并发的实现1、线程的实现方式一2、线程的实现方式二三、线程的生命周期1、线程的五个生命周期2、常用方法3、线程的sleep4、终止线程的睡眠状态5、强行终止线程的执行6、合理终止一个线程的执行四、线程的调度…

apache html调用bash脚本案例

首先安装apache服务,采用yum的方式即可,因为用到的都是apache的基本功能,不需要编译安装 yum -y install httpd 然后准备html页面,这个页面其实就是调用bash脚本的页面,提供页面操作然后调用服务器上的脚步文件 网页布局建议用…

【嵌入式UI框架:LVGL】使用恩智浦GUI设计工具,像Qt一样开发MCU界面

LVGL是一个免费的开源嵌入式图形库,它提供创建嵌入式GUI所需的功能,具有易于使用的图形元素、精美的视觉效果和低内存占用。完整的图形框架包括供您在创建GUI时所用的各种小部件,并支持更高级的功能,例如动画和抗锯齿。 一、工具&…

springcloud入门

微服务架构介绍 微服务架构, 简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独 立运行的项目。 微服务架构的常见问题 一旦采用微服务系统架构,就势必会遇到这样几个问题: 这么多小服务…

MYSQL——毫秒值和日期类型数据的转换,DATE_SUB的用法

MYSQL——毫秒值和日期类型数据的转换,DATE_SUB的用法一、毫秒值转换成日期数据类型二、日期数据类型转换成毫秒值三、DATE_SUB的用法一、毫秒值转换成日期数据类型 语法:FROM_UNIXTIME(毫秒值字段,‘%Y-%m-%d %h:%i:%s’) 举例: select id…

spring-boot-starter-aop及其使用场景说明

如今,AOP(Aspect Oriented Programming)已经不是什么崭新的概念了,在经历了代码生成、动态代理、字节码增强甚至静态编译等不同时代的洗礼之后,Java 平台上的 AOP 方案基本上已经以 SpringAOP 结合 AspectJ 的方式稳固…

基于独立分量分析进行模态分解(Matlab代码实现)

👨‍🎓个人主页:研学社的博客 💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜…

[附源码]计算机毕业设计基于Springboot在线教育系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

Mysql详细安装步骤

目录 1、解压服务端Mysql安装包 2.复制改变my.ini文件 3、安装MySQL服务 4、启动mysql服务 6.记录初始密码,利用初始密码登录 &7.改变MySQL链接密码 1、解压服务端Mysql安装包 解压之后的目录就是以上这样的。 2.复制改变my.ini文件 把my.ini文件添加…

【计算机图形学入门】笔记3:变换Transformation(二维与三维)

第三章.Transformation变换(二维与三维)1.为什么要学习变换?2.变换的几种形式1.缩放2.相对于y轴翻转3.Shear Matrix 切片4.旋转3.齐次坐标1.平移变换2.齐次坐标的引入3.使用齐次坐标表示上述变换4.组合变换5.分解变换6.三维空间中的变换1.三维…

QT 系统学习 day03 了解各种控件,文件操作,消息框,windows应用界面的 生成菜单栏, 状态栏,中心部件,工具栏,

1. 控件, 旋钮 ,进度条, 我也不知道叫啥, 相关的代码; 首先是函数 1.旋钮函数 (槽函数都有说明)(Dial) ui->dial->setRange(0,100);//设置旋钮的范围ui->di…

Three.js一学就会系列:01 第一个3D网站

文章目录前言一、Three.js是什么?官网官网示例效果尝鲜二、使用步骤1.引入three.js库2.使用方法创建一个场景创建一个透视摄像机将渲染器添加到页面上创建一个立方体渲染场景立方体动起来效果总结前言 最近开始入坑前端3D建站,跟大家一起慢慢深入three.…

Android 面试拒收Offer篇,这样做对吗?

作者:如梦 如梦朦胧 朋友们的劝说下,有了换工作的躁动,然后投了某度的Android岗位,本以为像我这种非211、985没工作经验的渣渣只能被直接pass,结果却意外的收到了电话,真是受宠若惊.经过电面,技术三面,然后就是等通知到最后拿到了OFFER,如梦一般,真是挺…

性能优化:Redis使用优化(1)

参考资料: 《Redis为什么变慢了?一文讲透如何排查Redis性能问题 | 万字长文》 相关文章: 《Redis:内存淘汰机制》 《Redis:持久化RDB与AOF》 《Redis:主从复制》 写在开头:本文为学习后的总…

Spring中事务失效的场景

文章目录1 抛出检查异常导致事务不能正确回滚1.1 异常演示1.2 解决办法2 业务方法内自己 try-catch 异常导致事务不能正常回滚1.1 异常演示1.2 解决办法3 aop切面顺序导致事务不能正确回滚3.1 异常演示3.2 解决办法4 非 public 方法导致事务的失效4.1 异常演示4.2 解决办法5 父…

深度学习-全卷积神经网络(FCN)

1. 简介 全卷积神经网络(Fully Convolutional Networks,FCN)是Jonathan Long等人于2015年在Fully Convolutional Networks for Semantic Segmentation一文中提出的用于图像语义分割的一种框架,是深度学习用于语义分割领域的开山之…