Django
用户登录认证系统
1. django
认证系统默认配置
django
框架安装后就自动带有一个用户认证系统和后台管理网站,帮助开发者使用。
1.1. 默认认证系统内容
django
默认已经提供了认证系统Auth
模块。认证系统包含:
- 用户管理
- 权限
- 用户组
- 密码哈希系统
- 用户登录或内容显示的表单和视图
- 一个可插拔的后台系统
admin
1.2. 默认认证系统用户模型
Django
认证系统中提供了用户模型类User保存用户的数据,默认的User包含以下常见的基本字段:
字段名 | 字段描述 |
---|---|
username | 必选。150个字符以内。 用户名可能包含字母数字,_ ,@ ,+ . 和- 个字符。 |
first_name | 可选(blank=True )。 少于等于30个字符。 |
last_name | 可选(blank=True )。 少于等于30个字符。 |
email | 可选(blank=True )。 邮箱地址。 |
password | 必选。 密码的哈希加密串。 (Django 不保存原始密码)。 原始密码可以无限长而且可以包含任意字符。 |
groups | 与Group 之间的多对多关系。 |
user_permissions | 与Permission 之间的多对多关系。 |
is_staff | 布尔值。 设置用户是否可以访问Admin 站点。 |
is_active | 布尔值。 指示用户的账号是否激活。 它不是用来控制用户是否能够登录,而是描述一种帐号的使用状态。 |
is_superuser | 是否是超级用户。超级用户具有所有权限。 |
last_login | 用户最后一次登录的时间。 |
date_joined | 账户创建的时间。 当账号创建时,默认设置为当前的date/time。 |
常用方法:
-
set_password
(raw_password)将原始密码加密。
-
check_password
(raw_password)如果给定的raw_password是用户的真实密码,则返回True,可以在校验用户密码时使用。
管理器方法:
管理器方法即可以通过User.objects.
进行调用的方法。
-
create_user(*username*, *email=None*, *password=None*, **\*extra_fields*)
创建、保存并返回一个
User
对象。 -
create_superuser(*username*, *email*, *password*, **\*extra_fields*)
与
create_user()
相同,但是设置is_staff
和is_superuser
为True
。
2. 自定义django
用户登录认证系统
在django.contrib.auth.models
中实现了一个User模型,但是该模型并不能满足我们项目的需要,比如我们要记录用户的手机,给用户添加头像等。 通过源码我们可以知道这个User继承自AbstractUser
的类,为此在项目里,我们也来继承自AbstractUser
创建一个适合本项目的用户模型。因为django
自带了后台管理系统,所以如需修改用户模型,最好在第一次迁移系统数据库时,就要建立自己的用户模型。这一点非常重要!
2.0. 系统集成xadmin
尽管django
集成了后台管理网站admin
,但是相对来说,功能比较简单,界面也比较简陋。为了提升后台功能,在项目中集成xadmin,xadmin
基于admin
构建,但是功能更加强大。
-
下载
xadmin
,在github
搜索并下载,这里需要注意要下载django2
所使用的xadmin
版本。 -
在项目根目录下创建一个文件夹,命名为
“extra_apps"
。并在此文件夹上右键单击,选择”Mark as“->“source root”。 -
在项目配置文件中把
extra_apps
添加到系统搜素目录。import sys BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.join(BASE_DIR, 'extra_apps'))
也可以使用pip安装
pip install https://codeload.github.com/sshwsfc/xadmin/zip/django2 -i pipy.douban.com/simple
2.1. 用户模型定义
在建立的users应用下面的models.py
定义该用户模型。代码如下:
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
mobile = models.CharField(max_length=15, unique=True, verbose_name="手机号码")
avatar = models.ImageField(upload_to='avaters', verbose_name="用户头像")
class Meta:
db_table = 'ly_user'
verbose_name = '用户信息'
verbose_name_plural = verbose_name
该用户模型建立后,需要添加到系统。
2.2. 为系统添加新的用户模型
打开项目设置文件settings.py
, 添加如下代码:
# 自定义用户模型
AUTH_USER_MODEL = 'users.User'
2.3. 生成迁移文件,并迁移数据库
在命令行终端输入如下代码:
第一步:python manage.py makemigrations
—生成迁移文件。
第二部:python manage.py migrate
—迁移数据库
进过上面的步骤,该项目就具有了一个符合需求的用户系统。
3. django rest framework JWT
认证
在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。抛弃django
内置的Session认证机制外,这里我们使用JWT(Json Web Token)
认证机制。
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
简单来说,JWT认证就是当用户登录时,服务器验证为合法用户后,会签发一个token,这个token就是一个加密字符串。客户端接收这个token后,访问设置了权限的页面时,必须携带token。当服务器收到后,会利用服务器保存的秘钥解密验证。
3.1. 安装配置JWT
安装:
pip3 install djangorestframework-jwt
配置:
在项目配置文件settings.py
中添加配置如下:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
}
import datetime
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
}
3.2. 后端实现登录认证接口
django rest framework JWT
提供了登录获取token的视图,可以简单配置后直接使用。
在应用的urls.py
中添加路由
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
path(r'login/', obtain_jwt_token),
]
上面的内置视图能自动生成token
并返回客户端。但是有时也需要手动生成token
,代码如下:
from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
当然还应该在项目主路由中引入该应用的路由。
4. 客户端保存JWT
jwt可以保存在cookie中,也可以保存在浏览器本地存储里,本项目jwt保存采用浏览器本地存储。sessionStorage
和localStorage
为两种不同的本地存储:
sessionStorage
浏览器关闭即失效localStorage
长期有效
4.1 本地存储的使用方法:
sessionStorage
的使用
//保存数据
sessionStorage.变量名 = 变量值
sessionStorage.setItem("变量名", "变量值")
// 读取数据
sessionStorage.变量名
sessionStorage.getItem("变量名")
// 清除单个数据
sessionStorage.removeItem("变量名")
// 清除所有sessionStorage保存的数据
sessionStorage.clear()
localStorage
的使用
//保存数据
localStorage.变量名 = 变量值
localStorage.setItem("变量名","变量值")
// 读取数据
localStorage.变量名
localStorage.getItem("变量名")
// 清除单个数据
localStorage.removeItem("变量名")
// 清除所有sessionStorage保存的数据
localStorage.clear()
5. 自定义jwt
返回值内容
jwt默认返回值仅有token
。有时其实需要更多的返回内容,比如要返回用户登录用户的id
和username
,方便在客户端页面中显示当前登录用户。
5.1. jwt
返回值定义
在users/utils.py
中,创建如下代码:
def jwt_response_payload_handler(token, user=None, request=None):
"""
自定义jwt认证成功返回数据
:param token: 本次登录成功后返回的jwt
:param user: 本次登录成功后,从数据库查询到的用户模型信息
:param request: 本次客户端的请求对象
:return:
"""
return {
"token": token,
"id": user.id,
"username": user.username
}
5.2. jwt
自定义返回值的设置
在项目settings.py
中的JWT_AUTH
添加如下代码:
JWT_AUTH = {
...
# 自定义返回数据的格式
'JWT_RESPONSE_PAYLOAD_HANDLER': 'users.utils.jwt_response_payload_handler',
}
6. django
多条件登录
django
允许您根据不同的条件进行身份验证。AUTHENTICATION_BACKENDS
为项目提供了一个认证后端列表。默认情况下,此设置设置如下:
['django.contrib.auth.backends.ModelBackend']
默认情况下,ModelBackend
是根据使用django.contrib.auth
中的用户模型建立的数据库进行认证用户的。这种情形会符合大部分项目需求。但是,也可以自定义一个后端,以便根据其他条件来认证一个用户,比如根据用户的email
,或者用户的电话号码等。
6.1. django
认证的流程
无论什么时候使用django.contrib.auth
中的authenticate()
,django
都会根据AUTHENTICATION_BACKENDS
设置,一个一个的尝试每一个认证后端,只要有一个成功,就算认证了这个用户。只有所有的认证后端都失败,那么就才不会授权用户登录系统。
6.2. django
自定义认证的原理
django
提供了一个简便的方法用来定义自己的认证后端。实际上,一个认证后端就是一个类,该类提供如下两个方法:
authenticate()
: 该方法接收request
对象和用户凭证作为参数。如果用户凭证合法,那么应该返回一个满足这个凭证的用户,否则返回None
。request
参数就是一个HttpRequest
对象。get_user()
: 接收一个ID参数,返回一个用户对象。
6.3. 自定义手机登录认证
在users/utils.py
中添加如下代码:
class MobileAuthBackend:
'''
通过手机验证用户
'''
def authenticate(self, request, username=None, password=None):
try:
user=User.objects.get(mobile=username)
if user.check_password(password):
return user
return None
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
在项目settings.py
中进行配置:
# 多条件登录认证
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'users.utils.MobileAuthBackend',
]
进过上面两部后,客户端就可以通过用户名、密码登录,也可以使用手机号和密码登录了。