from rest_framework.authentication import BaseAuthentication from rest_framework import exceptions import jwt from .utils import jwt_get_user_id_from_payload_handler, jwt_decode_handler from user.models import User from .settings import api_settings class JWTAuthentication(BaseAuthentication): www_authenticate_realm = 'api' def authenticate(self, request): """ Returns a two-tuple of `User` and token if a valid signature has been supplied using JWT-based authentication. Otherwise returns `None`. """ jwt_value = self.get_jwt_value(request) if jwt_value is None: return None try: payload = jwt_decode_handler(jwt_value) except jwt.ExpiredSignature: msg = 'Token过期' raise exceptions.AuthenticationFailed({"message": msg,"errorCode":1,"data":{}}) except jwt.DecodeError: msg = 'Token不合法' raise exceptions.AuthenticationFailed({"message": msg,"errorCode":1,"data":{}}) except jwt.InvalidTokenError: raise exceptions.AuthenticationFailed() user = self.authenticate_credentials(payload) return user, jwt_value def authenticate_credentials(self, payload): id = jwt_get_user_id_from_payload_handler(payload) if not id: raise exceptions.AuthenticationFailed({"message": "没有该用户","errorCode":1,"data":{}}) try: user = User.objects.filter(id=id).first() except User.DoesNotExist: raise exceptions.AuthenticationFailed({"message": "没有该用户","errorCode":1,"data":{}}) return user def get_jwt_value(self, request): auth = request.META.get('HTTP_AUTHORIZATION', '').split() auth_header_prefix = api_settings.JWT_AUTH_HEADER_PREFIX.lower() if not auth or auth[0].lower() != auth_header_prefix: return None if len(auth) == 1: msg = 'Invalid Authorization header. No credentials provided.' raise exceptions.AuthenticationFailed({"message": "消息头不合法","errorCode":1,"data":{}}) elif len(auth) > 2: msg = 'Invalid Authorization header. Credentials string should not contain spaces.' raise exceptions.AuthenticationFailed({"message": "消息头不合法","errorCode":1,"data":{}}) return auth[1] def authenticate_header(self, request): """ Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. """ return '{0} realm="{1}"'.format(api_settings.JWT_AUTH_HEADER_PREFIX, self.www_authenticate_realm)