Django rest framework给我们提供了很强大的功能,由于自带的token认证没有过期时间,而且token数据是保存在数据库的,这样一来无疑是加大了对数据库的压力,所以这是我们就可以使用jwt认证,jwt认证全称为json web token,他是通过加密解密进行认证的,用户的信息全部保存在加密体中(当然不会对敏感信息进行存放),由前端发送用户信息给后台,后台将信息加密返回给前端,然后前端保存在本地,每次请求的时候带着这个加密数据进行请求,这样一来,对于服务器来说就不会有很大的压力,当然这样做是会加大服务器的计算,但jwt认证的好处不只是这样,他还有利于对分布式部署的支持。
当登录成功时jwt是默认只返回token信息的,当有些时候仅有一个token是不满足我们系统的,所以这时候我们需要对返回方法进行重写,代码如下:
def jwt_response_payload_handler(token, user=None, request=None, role=None):
"""
自定义jwt返回数据
"""
if user.first_name:
name = user.first_name
else:
name = user.username
return {
"msg": "success",
"status": 200,
"data": [{
'id': user.id,
"role": role,
'email': user.email,
'name': name,
'username': user.username,
'token': token,
}]
}
方法完成后我们需要前往setting中对jwt进行配置,修改JWT_RESPONSE_PAYLOAD_HANDLER参数为刚刚方法:
# jwt载荷中的有效期设置
JWT_AUTH = {
'JWT_AUTH_HEADER_PREFIX': 'JWT',
# token 有效期
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=3),
'JWT_ALLOW_REFRESH': True,
# 续期有效期(该设置可在24小时内带未失效的token 进行续期)
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(hours=24),
# 自定义返回格式,需要手工创建
'JWT_RESPONSE_PAYLOAD_HANDLER': 'apps.users.views.jwt_response_payload_handler',
# 'JWT_RESPONSE_PAYLOAD_ERROR_HANDLER': 'apps.users.views.jwt_response_payload_error_handler',
}
登录失败信息自定义这里有两种方法,第一种就是修改django rest framework jwt的源码:
首先进入rest_framework_jwt的setting中在DEFAULTS中添加:
# 自定义ERROR返回
'JWT_RESPONSE_PAYLOAD_ERROR_HANDLER': 'rest_framework_jwt.utils.jwt_response_payload_error_handler',
然后在IMPORT_STRINGS中添加:
# 自定义ERROR返回
'JWT_RESPONSE_PAYLOAD_ERROR_HANDLER',
当修改好后,进入rest_framework_jwt的views里面添加:
jwt_response_payload_error_handler = api_settings.JWT_RESPONSE_PAYLOAD_ERROR_HANDLER
并修改post方法的失败返回值:
这样一来我们源码就修改好了,然后就可以像自定义成功返回值一样,自己编写方法然后去setting中进行配置就行了:
自定义失败返回方法:
def jwt_response_payload_error_handler(serializer, request=None):
return {
"msg": "用户名或者密码错误",
"status": 400,
"detail": serializer.errors
}
setting配置:
当然这样直接修改源码会有一个问题,就是每次我们重新部署的时候都需要去修改源码,这样做的话会很麻烦,所以我们可以在工程目录下创建一个包,然后将修改好的源码放进去,这样一来的话我们就不必要每次都去修改jwt的源码,但是,想要使用包中修改的源码我们需要在setting中增加一个配置,这样需要找包就优先前往这个包里找源码了:
当然这是第一种修改方式,还有一种修改方式是自定义middleware,然后通过middleware对response进行修改,话不多说,直接上代码:
class ExceptionChange:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
return response
def process_template_response(self, request, response):
if hasattr(response, 'data'):
data = response.data
print(type(data))
if "non_field_errors" in data.keys():
if data['non_field_errors'] == ["无法使用提供的认证信息登录。"]:
del response.data['non_field_errors']
response.data['msg'] = '用户名或者密码错误'
response.data['status'] = '400'
elif "detail" in data.keys():
del response.data["detail"]
response.data["status"] = response.status_code
response.data["msg"] = "请先登录系统"
return response
然后前往setting中将该方法配置到middleware中去,这里值得注意的是,django的middleware调用方法是请求的时候从上往下,返回的时候从下往上,所以这里我们直接将我们的方法放到最下方:
对于这两种方法我更倾向于第二种,因为这样通过middleware的修改返回值的好处不关可以处理jwt的登录请求,还能将django其他的失败返回也进行处理,这样可以更方便的进行我们的接口定制,当然因为我是一个初学者,我不知道其他的返回信息有没有更好的修改方法,当然如果有大佬知道其他更好的办法欢迎留言。