django实现登录的时候肯定要生成jwt来进行会话保持
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
基于token的鉴权机制,不需要在服务端去保留用户的认证信息。这就意味着应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。
流程:
· 用户使用`用户名密码`来请求服务器
· 服务器进行验证用户的信息
· 服务器通过验证发送给用户一个token
· 客户端存储token,并在每次请求时附送上这个token值
· 服务端验证token值,并返回数据
就像这样:
# JWT字符串
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签名(signature).
将这三部分用`.`连接成一个完整的字符串,构成了最终的jwt
首先安装
pip install djangorestframework-jwt
在setting里面配置
REST_FRAMEWORK = {
# 身份认证
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
}
import datetime
JWT_AUTH = {
# jwt过期时间
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
}
设置路由
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
path('login/', obtain_jwt_token), #视图函数
]
注:看这里是否设置了主路由,如果设置请求地址记得加上主路由
请求地址: http://127.0.0.1:8000/users/login/
请求方式: post
请求参数:表单
参数名 | 类型 | 是否必须 | 说明 |
---|---|---|---|
username | str | 是 | 用户名 |
password | str | 是 | 密码 |
返回数据: JSON
{
"username": "zhangsan",
"user_id": 1,
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo5LCJ1c2VybmFtZSI6InB5dGhvbjgiLCJleHAiOjE1MjgxODI2MzQsImVtYWlsIjoiIn0.ejjVvEWxrBvbp18QIjQbL1TFE0c0ejQgizui_AROlAU"
}
返回数据说明:
返回值 | 类型 | 是否必须 | 说明 |
---|---|---|---|
username | str | 是 | 用户名 |
id | int | 是 | 用户id |
token | str | 是 | 身份认证凭据 |
注:djangorestframework-jwt默认只返token回
def jwt_response_payload_handler(token, user=None, request=None):
"""为返回的结果添加用户相关信息"""
return {
'token': token,
'user_id': user.pk,
'username': user.username,
}
修改settings.py中的配置
# JWT配置
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
# 自定义返回数据
'JWT_RESPONSE_PAYLOAD_HANDLER': 'users.myutils.jwt_response_payload_handler',
}
djangorestframework-jwt扩展的登录视图,在收到用户名与密码时,也是调用Django的认证系统中提供的authenticate()来检查用户名与密码是否正确。
我们可以通过修改Django认证系统的认证后端
(主要是authenticate方法)来支持登录账号既可以是用户名也可以是手机号。
修改Django认证系统的认证后端需要继承django.contrib.auth.backends.ModelBackend
,并重写authenticate方法。
authenticate(self, request, username=None, password=None, **kwargs)
方法的参数说明:
request 本次认证的请求对象
username 本次认证提供的用户账号
password 本次认证提供的密码
我们想要让管理员用户才能登录我们的admin后台,这时我们就要修改django原有的用户验证方法。
重写authenticate方法的思路:
根据username查找用户User对象,在查询条件中在加上is_staff=True的条件
若查找到User对象,调用check_password方法检查密码是否正确
代码如下:
from django.contrib.auth.hashers import check_password
from users.models import User
class IsAdminBackend(ModelBackend):
def authenticate(self, request, username=None, password=None):
# 根据前台提交的数据获取用户对象,
user = User.objects.filter(username=username, is_staff=True).first()
# 判断用户是否存在并且密码是否正确
if user and check_password(password, user.password):
# 判断通过,返回用户对象
return user
# 用户不存在或者密码不正确时
else:
return None
配置settings.py中的==django认证==
# 只能配置一个认证类,走找到的第一个,并且认证不通过返回400
# 认证通过返回json数据{token:xxx, xxx,xxx}
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend', # djangp默认认证
'users.utils.IsAdminBackend', # 自定义认证
]
这样就能实现登录生成JWT-TOKEN