restframework-jwt执行流程(签发流程、认证)、双token认证、过期时间
restframework-jwt执行流程
from rest_framwork_jwt.views import obtain_jwt_token, refresh_jwt_token, verity_jwt_token
obtain_jwt_token:签发token
refresh_jwt_token:刷新token
verity_jwt_token:验证token
签发流程
本质就是登录接口-->校验用户是否正确,如果正确签发token,如果不正确,返回错误
django中顶格写的代码直接执行
# obtain_jwt_token
核心代码:ObtainJSONWebToken.as_view()
ObtainJSONWebToken视图类,实现了登录的功能
class ObtainJSONWebToken(JSONWebTokenAPIView):
serializer_class = JSONWebTokenSerializer
"""父类ObtainJSONWebToken"""
class JSONWebTokenAPIView(APIView):
# 局部禁用掉权限和认证
permission_classes = ()
authentication_classes = ()
def get_serializer_context(self):
return {
'request': self.request,
'view': self,
}
def get_serializer_class(self):
return self.serializer_class
def get_serializer(self, *args, **kwargs):
serializer_class = self.get_serializer_class()
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
def post(self, request, *args, **kwargs):
# JSONWebTokenSerializer实例化得到一个序列号类的对象,传入前端传的只
serializer = self.get_serializer(data=request.data)
if serializer.is_valid(): # 校验前端传入的数据是否合法:
#1 字段自己的规则 2 局部钩子 3 全局钩子(序列化类的validate方法)
# 获取当前登录用户和签发token是在序列化类中完成的
# 从序列化类对象中取出了当前登录用户
user = serializer.object.get('user') or request.user
# # 从序列化类对象中取出了token
token = serializer.object.get('token')
# 自定义过
response_data = jwt_response_payload_handler(token, user, request)
response = Response(response_data)
return response
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
"""序列化类:JSONWebTokenSerializer"""
class JSONWebTokenSerializer(Serializer):
def validate(self, attrs):
credentials = {
'username': attrs.get('username'),
'password': attrs.get('password')
}
if all(credentials.values()):
# auth的校验用户名和密码是否正确
user = authenticate(**credentials)
if user:
# 通过用户获得payload:{}
payload = jwt_payload_handler(user)
return {
'token': jwt_encode_handler(payload),
'user': user
}
else:
# 根据用户名和密码查不到用户
raise serializers.ValidationError(msg)
else:
# 用户名和密码不传,传多了都不行
raise serializers.ValidationError(msg)
认证
"""认证类;JSONWebTokenAuthentication"""
class JSONWebTokenAuthentication(BaseJSONWebTokenAuthentication):
def get_jwt_value(self, request):
# get_authorization_header(request)根据请求头中HTTP_AUTHORIZATION,取出token
# jwt adsfasdfasdfad
# auth=['jwt','真正的token']
auth = get_authorization_header(request).split()
auth_header_prefix = api_settings.JWT_AUTH_HEADER_PREFIX.lower()
if not auth:
if api_settings.JWT_AUTH_COOKIE:
return request.COOKIES.get(api_settings.JWT_AUTH_COOKIE)
return None
if smart_text(auth[0].lower()) != auth_header_prefix:
return None
if len(auth) == 1:
msg = _('Invalid Authorization header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid Authorization header. Credentials string '
'should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
return auth[1]
"""父类中:BaseJSONWebTokenAuthentication---》authenticate"""
class BaseJSONWebTokenAuthentication(BaseAuthentication):
def authenticate(self, request):
# jwt_value前端传入的token
jwt_value = self.get_jwt_value(request)
# 前端没有传入token,return None,没有带token,认证类也能过,所有咱们才加权限类
if jwt_value is None:
return None
try:
payload = jwt_decode_handler(jwt_value) # 验证token,token合法,返回payload
except jwt.ExpiredSignature:
msg = _('Signature has expired.')
raise exceptions.AuthenticationFailed(msg)
except jwt.DecodeError:
msg = _('Error decoding signature.')
raise exceptions.AuthenticationFailed(msg)
except jwt.InvalidTokenError:
raise exceptions.AuthenticationFailed()
user = self.authenticate_credentials(payload) # 通过payload得到当前登录用户
return (user, jwt_value) # 后期的request.user就是当前登录用户
# 它这个认证类:只要带了token,request.user就有只,如果没带token,不管了,继续往后走
设置过期时间
签发的token,有过期时间,过期时间是?配置一般设为7天,默认是五分钟
'JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
}'
双token认证
用户正在app或者应用中操作 token突然过期,此时用户不得不返回登陆界面,重新进行一次登录,这种体验性不好,于是引入双token校验机制
实现原理:首次登陆时服务端返回两个token ,accessToken和refreshToken,accessToken过期时间比较短,refreshToken时间较长,且每次使用后会刷新,每次刷新后的refreshToken都是不同
refreshToken假设7天,accessToken过期时间5分钟
以后带着accessToken访问就好了,校验也是accessToken,
当accessToken过期了,校验refreshToken,然后在生成一个accessToken当。
refreshToken过期以后,refreshToken与accessToken一起过期的机率比较小,如果真的同时失效了,那就重新登录一次。
正常使用accessToken即可,如果accessToken过期了,重新发请求,携带refreshToken过来,能正常返回,并且这次响应中又带了acessToken