文章目录
- 快速上手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 默认使用用户认证的是ModelBackend
的authenticate()
方法,这个方法就是登录时对用户认证的方法。我们要改的就是这个方法。
思路:继承ModelBackend
重写authenticate
方法、get_user
方法。
认证后端是一个类,它实现了两个必要的方法get_user(user_id) 和 authenticate(request, **credentials)。
- get_user 方法接收一个 user_id ——可以是用户名、电话号码,或者其他唯一标识用户的信息——然后返回一个用户对象或 None。
- 覆写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