一、定义用户模型类
1.1 django默认用户模型类
Django认证系统中提供了用户模型类User保存用户的数据。
- User对象是认证系统的核心。
Django认证系统用户模型类位置
- django.contrib.auth.models.User
class User(AbstractUser):
"""
Users within the Django authentication system are represented by this
model.
Username and password are required. Other fields are optional.
"""
class Meta(AbstractUser.Meta):
swappable = "AUTH_USER_MODEL"
父类AbstractUser
介绍:
- User对象的基本属性:
-
- 创建用户(注册用户)必选:username、password
- 创建用户(注册用户)可选: email、first_name、last_name、last_login、date_joined、 is_active 、is_staff、is_superuser
- 判断用户是否通过认证(是否登录): is_authenticated
- 创建用户(注册用户)的方法:
user = User.objects.create_user(username, email, password, **extra_fields)
- 用户认证(用户登录)的方法:
from django.contrib.auth import authenticate
user = authenticate(username=username, password=password, **kwargs)
- 处理密码的方法:
-
- 设置密码: set_password(raw_password)
- 校验密码: check_password(raw_password)
1.2 自定义用户模型类
思考:为什么要自定义用户模型类??
- 如今几乎所有的web应用都需要用户提供手机号码,单默认的用户模型类中没有mobile字段
- 随着业务的发展,未来很可能需要自定义用户模型
- django强烈推荐在开始一个项目时设置一个自定义的用户模型
如何自定义模型类??
- 继承自AbstractUser(最简单可行的方法,详情见官方文档)
- 新增 mobile 字段
在 users.models.py
模块中定义模型如下:
import re
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.core.exceptions import ValidationError
def validate_mobile(value):
if not re.match(r'1[3-9]\d{9}', value):
raise ValidationError('手机号码格式不正确')
class User(AbstractUser):
"""
Custom user model.
Add mobile field to Django user model
"""
mobile = models.CharField(
'手机号码', max_length=11, unique=True, help_text='手机号码', null=True, blank=T
error_messages={'unique': '手机号码已注册'}, validators=[validate_mobile])
REQUIRED_FIELDS = ['mobile'] # 在通过 createsuperuser 管理命令创建用户时,将提示输入
mobile字段
def __str__(self):
return self.username
class Meta:
db_table = 'tb_user' # 表名
verbose_name = 'user' # 站点显示名
verbose_name_plural = 'users' # 复数显示
1.3 知识要点:
1. Django自带用户认证系统,核心就是User对象,并封装了一系列可用的方法和属性。
2. Django用户认证系统包含了一系列对用户的操作,比如:模型类,认证,权限,分组,密码处理等。
3. Django用户认证系统中的用户模型类可以自定义,最简单的方法是继承自AbstractUser。
4. 更多Django中的自定义验证见官方文档
二、迁移用户模型类
2.1 指定用户模型类
Django是通过配置项 AUTH_USER_MODEL
来确定项目中到底使用哪个用户模型,所以我们需要修改配置指定我们的自 定义的用户模型。
配置规则:
# AUTH_USER_MODEL = '应用名.模型类名'
# 指定本项目用户模型类 settings.py 设置,【应用名.模型名】
AUTH_USER_MODEL = 'users.User'
2.2 迁移用户模型类
python manage.py makemigrations
python manage.py migrate
2.3 知识要点
1. 用 户 认 证 系 统 中 所用的 用 户 模 型 类 , 是 通 过 全 局 配 置 项 AUTH_USER_MODEL
决 定 的 。
2. 如 果 迁 移 自 定 义 用 户 模 型 类 , 必 须 先 配 置 AUTH_USER_MODEL
。
3. 注 意 在 迁 移 之 前 , 运 行 服 务 会 报 错 , 因 为 默 认 项 目 依 赖 用 户 模 型
2.4 创建一个超级管理员
使用一下命令:
python .\manage.py createsuperuser
三、用户认证
身份验证是将传入请求与一组标识凭据(例如请求来自的用户或用于签名的令牌)相关联的机制。然后,权限和限制 策略可以使用这些凭据来确定是否应该允许请求。
3.1 安装RESTframwork
安装:
pip install djangorestframework
注册:
在配置 INSTALLED_APPS
中添加 restframework
INSTALLED_APPS = [
...
'rest_framework'
]
3.2 用户认证方案
REST framework 提供了许多开箱即用的身份验证方案,还允许您实现自定义方案
3.2.1 BasicAuthentication
此身份验证方案使用HTTP 基本身份验证,根据用户的用户名和密码进行签名。基本身份验证通常仅适用于测 试。
3.2.2 TokenAuthentication
此身份验证方案使用简单的、基于令牌的 HTTP 身份验证方案。令牌身份验证适用于客户端-服务器设置,例如,本机桌面和移动客户端。
要使用 TokenAuthentication
方案,您需要配置身份验证类以包含 TokenAuthentication ,并另外包含 rest_framework.authtoken
在您的 INSTALLED_APPS
设置中:
INSTALLED_APPS = [
...
'rest_framework.authtoken'
]
因为token保存在数据中,所以还需要数据库迁移。
3.2.3 SessionAuthentication
此身份验证方案使用 Django 的默认会话后端进行身份验证。会话身份验证适用于在与您的网站相同的会话上 下文中运行的 AJAX 客户端。
特点:
- 保持在服务端, 增加服务器开销
- 分布式架构中, 难以维持Session会话同步
- CSRF攻击风险
3.2.4 JSON Web Token认证
JSON Web Token 是一个相当新的标准,可用于基于令牌的身份验证。与内置TokenAuthentication 方案不 同,JWT Authentication 不需要使用数据库来验证令牌。
jwt原理:
JSON Web Token (缩写JWT)是目前最流行的跨域认证解决方案。
jwt的原理是,服务器认证以后,生成一个JSON对象,发回给用户,就像下面这样。
{
"姓名": "心蓝",
"角色": "管理员",
"到期时间": "2020年10月1日0点0分"
}
以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户 篡改数据,服务器在生成这个对象的时候,会加上签名(详见后文)。 服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。
JWT的数据结构
实际的 JWT 大概就像下面这样。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VybmFtZSI6InB5MzQiLCJleHAiOiIxNjAxNDU4ODI2LjM5MjU5NyJ9.
e1c994e615cfbf3a81a13076b7d05c98a752bbd9381f551ad568ef287d439980
它是一个很长的字符串,中间用点(.)分隔成三个部分。注意,JWT 内部是没有换行的,这里只是为了便于展示, 将它写成了几行。
JWT 的三个部分依次如下。
- Header(头部)
是可以解密的,这个相当于一个算法协议,告诉服务器这个串是怎么加密的
- Payload(负载)
是可以解密的,解密之后,类似于以下这种效果:
{
"姓名": "心蓝",
"角色": "管理员",
"到期时间": "2020年10月1日0点0分"
}
- Signature(签名)
不能被解密
注意:
认证原理:服务器会根据JWT提供的头、负载,然后进行特殊的算法,生成一个签名数据,让签名(请求中带的)与签名(新生成的)对比,如果正确则认证成功
JWT的使用方式:
客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。 此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域, 所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。
Authorization: Bearer
另一种做法是,跨域的时候,JWT 就放在 POST 请求的数据体里面。
特点:
- 保存在客户端 跨语言、跨平台
- 拓展性强
- 鉴权性能高
本项目使用此种验证
3.3 设置认证方案
3.3.1 安装JWT插件
RESTframework没有实现jwt验证,第三方包djangorestframework-simplejwt 提供了可拔插的jwt验证功能。
使用pip进行安装:
pip install djangorestframework-simplejwt
并在 INSTALLED_APPS 中注册
INSTALLED_APPS = [
...
'rest_framework_simplejwt',
...
]
3.3.2 配置认证的类
RESTframework使用配置 DEFAULT_AUTHENTICATION_CLASSES
来设置默认的全局用户验证方案。在项目配置 中添加如下配置:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication', #
'rest_framework.authentication.SessionAuthentication', # session鉴权
]
}
REST framework 将尝试对列表中的每个类进行身份验证,并将设置 request.user 和 request.auth 使用成 功身份验证的第一个类的返回值。 如果没有类进行身份验证, request.user 则将设置为的实例
django.contrib.auth.models.AnonymousUser ,并将 request.auth 设置为 None 。 上面的配置表示先进行jwt验证,如果不成功就是使用session验证。
问题一:为什么要设置session鉴权??
因为以这种方式进行登录时,需要session鉴权,而且也需要在根路由中设置