在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用Json Web Token认证机制。
首先先声明以下本次进行登陆验证操作的环境:
Django框架中,在项目名同名的文件包下创建一个users子应用(正常流程下,咱们在注册时,已经将这个子应用创建好了);具体的一些文件可以参考下图。
当前,在使用JWT之前,我相信大家应该知道把JWT安装一下的吧
pip install djangorestframework-jwt
Django REST framework JWT提供了登录签发JWT的视图,可以直接使用;
也就是说,这个JWT已经把咱们需要进行登陆验证的视图给咱们写好了,咱们现在只需要在urls中将视图进行相关的注册就可以了;
在 users/urls.py 中,将下面一段注册路由的代码加入:
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
url(r'^authorizations/$', obtain_jwt_token),
]
咱们可以来看一下,这个obtain_jwt_token
视图函数,是如何进行相关验证的;(源码讲解开始)
obtain_jwt_token
中进去看一下这个obtain_jwt_token是什么样的视图函数,图片如下:ObtainJSONWebToken
这个视图函数中;JSONWebTokenAPIView
使用用户的用户名和密码接收POST的API视图。
返回可用于经过身份验证的请求的JSON Web令牌。
JSONWebTokenSerializer
JSONWebTokenAPIView
这个继承的类视图实现了什么功能:def post
里面具体实现的内容:if serializer.is_valid():
这个是在序列化器的验证完成并返回True的情况下可以进行下面的操作,这个验证我们下面后续会讲解;response_data = jwt_response_payload_handler(token, user, request)
的操作,我们再看一下这段代码的实现内容;from rest_framework_jwt.utils import jwt_response_payload_handler
获取 jwt_response_payload_handler
,如下:def jwt_response_payload_handler(token, user=None, request=None):
"""
Returns the response data for both the login and refresh views.
Override to return a custom response such as including the
serialized representation of the User.
Example:
def jwt_response_payload_handler(token, user=None, request=None):
return {
'token': token,
'user': UserSerializer(user, context={'request': request}).data
}
翻译:返回登录视图和刷新视图的响应数据。
覆盖以返回自定义响应,例如包括用户的序列化表示。
例:
def jwt_response_payload_handler(token,user = None,request = None):
返回{
'token':token,
'user':UserSerializer(user,context = {'request':request})。data
}
"""
return {
'token': token
}
也就是说,这个jwt_response_payload_handler
就是处理响应数据,进行序列化返回的;
那么我们的JSONWebTokenAPIView
就是在之前的Response基础上,增加了token值的返回,当然,处理之后,还是会将response = Response(response_data)
,然后再返回这对于我们下面说的自定义jwt_response_payload_handler
,自定义我们需要进行返回的数据;
JSONWebTokenSerializer
这个序列化器具体做了什么;Serializer类用于验证用户名和密码。
'username’由自定义UserModel.USERNAME_FIELD标识。
返回可用于验证以后调用的JSON Web令牌。
原来是用来验证用户名和密码是否匹配的,那么再看一下是如何验证的;
user = authenticate(**credentials)
这个是先进行解包,在进行authenticate的用户名和密码的验证;关于authenticate的用法介绍,我在这里截取一段文字供参考:
也就是说,在进行authenticate验证后,如果用户名和密码验证通过的话,那么就返回一个user对象,后期的login登陆的话,用户的数据信息就可以从这个对象里面进行获取并登陆了。
也就是说,如果我们需要进行更多的信息需要验证,那么我们可以改写这个authenticate
函数,当然,是需要继承我们的ModelBackend
类;
在users/utils.py中增加下面的代码;
def jwt_response_payload_handler(token, user=None, request=None):
return {
'token': token,
'user_id': user.id,
'username': user.username
}
在主文件的settings.py中也是需要对配置信息进行修改的:
JWT_AUTH = {
"""设置处理时使用的函数,就是上一步我们自己定义的那一个"""
'JWT_RESPONSE_PAYLOAD_HANDLER': 'users.utils.jwt_response_payload_handler',
}
def get_user_account(account):
"""判断用户登陆的是用户名还是手机号"""
try:
if re.match('^1[3-9]\d{9}$', account):
user = User.objects.get(mobile=account)
else:
user = User.objects.get(username=account)
except User.DoesNotExist:
raise None
return user
# 自定义Django的认证,满足多账号的登陆
class UsernameMobileAuthBackend(ModelBackend):
"""对用户进行密码身份的校验"""
def authenticate(self, request, username=None, password=None, **kwargs):
user = get_user_account(username)
if not user and user.check_password(password):
"""如果用户密码校验成功,返回用户模型对象,当然了,如果用户不存在,那么就不用再返回None了,因为在调用函数的时候
就返回None"""
return user
我们改写之后,还需要告诉Django,现在需要使用我们自定义的认证方法,我们就需要在settings.py中申明一下:
AUTHENTICATION_BACKENDS = [
'users.utils.UsernameMobileAuthBackend',
]