django rest framework_jwt之認證的原始碼流程剖析
阿新 • • 發佈:2018-11-20
檢視程式碼
1 class UserViewset(BaseView): 2 ''' 3 create: 4 建立使用者 5 retrieve: 6 7 ''' 8 queryset = User.objects.all() 9 authentication_classes = (JSONWebTokenAuthentication, authentication.SessionAuthentication) #認證類 10 def get_serializer_class(self):11 if self.action == "retrieve": 12 return UserDetailSerializer 13 elif self.action == "create": 14 return UserRegSerializer 15 16 return UserDetailSerializer 17 18 def get_permissions(self): 19 if self.action == "retrieve": 20 return[permissions.IsAuthenticated()] 21 elif self.action == "create": 22 return [] 23 24 return [] 25 26 def create(self, request, *args, **kwargs): 27 serializer = self.get_serializer(data=request.data) 28 serializer.is_valid(raise_exception=True) 29 user = self.perform_create(serializer)30 re_dict = serializer.data 31 payload = jwt_payload_handler(user) 32 re_dict["token"] = jwt_encode_handler(payload) 33 re_dict["name"] = user.name if user.name else user.username 34 35 headers = self.get_success_headers(serializer.data) 36 return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers) 37 38 def get_object(self): 39 return self.request.user 40 41 def perform_create(self, serializer): 42 return serializer.save()
認證類JSONWebTokenAuthentication程式碼:
1 class JSONWebTokenAuthentication(BaseJSONWebTokenAuthentication): 2 """ 3 Clients should authenticate by passing the token key in the "Authorization" 4 HTTP header, prepended with the string specified in the setting 5 `JWT_AUTH_HEADER_PREFIX`. For example: 6 7 Authorization: JWT eyJhbGciOiAiSFMyNTYiLCAidHlwIj 8 """ 9 www_authenticate_realm = 'api' 10 11 def get_jwt_value(self, request): 12 auth = get_authorization_header(request).split() #獲取請求裡面的token 13 auth_header_prefix = api_settings.JWT_AUTH_HEADER_PREFIX.lower() #獲取認證方式 14 15 if not auth: #如果沒有token就獲取其cookie 16 if api_settings.JWT_AUTH_COOKIE: 17 return request.COOKIES.get(api_settings.JWT_AUTH_COOKIE) 18 return None 19 20 if smart_text(auth[0].lower()) != auth_header_prefix: #看看是不是jwt認證 21 return None 22 23 if len(auth) == 1: #認證的字元必須是由空格隔開的字元 24 msg = _('Invalid Authorization header. No credentials provided.') 25 raise exceptions.AuthenticationFailed(msg) 26 elif len(auth) > 2: 27 msg = _('Invalid Authorization header. Credentials string ' 28 'should not contain spaces.') 29 raise exceptions.AuthenticationFailed(msg) 30 31 return auth[1] 32 33 def authenticate_header(self, request): 34 """ 35 Return a string to be used as the value of the `WWW-Authenticate` 36 header in a `401 Unauthenticated` response, or `None` if the 37 authentication scheme should return `403 Permission Denied` responses. 38 """ 39 return '{0} realm="{1}"'.format(api_settings.JWT_AUTH_HEADER_PREFIX, self.www_authenticate_realm) #返回響應
在父類BaseJSONWebTokenAuthentication中做認證判斷:
1 class BaseJSONWebTokenAuthentication(BaseAuthentication): 2 """ 3 Token based authentication using the JSON Web Token standard. 4 """ 5 6 def authenticate(self, request): #開始認證 7 """ 8 Returns a two-tuple of `User` and token if a valid signature has been 9 supplied using JWT-based authentication. Otherwise returns `None`. 10 """ 11 jwt_value = self.get_jwt_value(request) #獲取token 12 if jwt_value is None: 13 return None 14 15 try: 16 payload = jwt_decode_handler(jwt_value) #獲取使用者的token的實體 17 except jwt.ExpiredSignature: 18 msg = _('Signature has expired.') 19 raise exceptions.AuthenticationFailed(msg) 20 except jwt.DecodeError: 21 msg = _('Error decoding signature.') 22 raise exceptions.AuthenticationFailed(msg) 23 except jwt.InvalidTokenError: 24 raise exceptions.AuthenticationFailed() 25 26 user = self.authenticate_credentials(payload) #獲取使用者 27 28 return (user, jwt_value) 29 30 def authenticate_credentials(self, payload): 31 """ 32 Returns an active user that matches the payload's user id and email. 33 """ 34 User = get_user_model() 35 username = jwt_get_username_from_payload(payload) #獲取使用者名稱 36 37 if not username: 38 msg = _('Invalid payload.') 39 raise exceptions.AuthenticationFailed(msg) 40 41 try: 42 user = User.objects.get_by_natural_key(username) #獲取使用者 43 except User.DoesNotExist: 44 msg = _('Invalid signature.') 45 raise exceptions.AuthenticationFailed(msg) 46 47 if not user.is_active: 48 msg = _('User account is disabled.') 49 raise exceptions.AuthenticationFailed(msg) 50 51 return user
使用者請求進來以後,首先進入dispatch函式:
1 def dispatch(self, request, *args, **kwargs): 2 """ 3 `.dispatch()` is pretty much the same as Django's regular dispatch, 4 but with extra hooks for startup, finalize, and exception handling. 5 """ 6 self.args = args 7 self.kwargs = kwargs 8 request = self.initialize_request(request, *args, **kwargs) #載入新增的認證類 9 self.request = request 10 self.headers = self.default_response_headers # deprecate? 11 12 try: 13 self.initial(request, *args, **kwargs) #初始化request 14 15 # Get the appropriate handler method 16 if request.method.lower() in self.http_method_names: 17 handler = getattr(self, request.method.lower(), 18 self.http_method_not_allowed) 19 else: 20 handler = self.http_method_not_allowed 21 22 response = handler(request, *args, **kwargs) 23 24 except Exception as exc: 25 response = self.handle_exception(exc) 26 27 self.response = self.finalize_response(request, response, *args, **kwargs) 28 return self.response
載入initialize_request:
1 def initialize_request(self, request, *args, **kwargs): 2 """ 3 Returns the initial request object. 4 """ 5 parser_context = self.get_parser_context(request) 6 7 return Request( 8 request, 9 parsers=self.get_parsers(), 10 authenticators=self.get_authenticators(),載入新增的認證類 11 negotiator=self.get_content_negotiator(), 12 parser_context=parser_context 13 )
初始化initial:
1 def initial(self, request, *args, **kwargs): 2 """ 3 Runs anything that needs to occur prior to calling the method handler. 4 """ 5 self.format_kwarg = self.get_format_suffix(**kwargs) 6 7 # Perform content negotiation and store the accepted info on the request 8 neg = self.perform_content_negotiation(request) 9 request.accepted_renderer, request.accepted_media_type = neg 10 11 # Determine the API version, if versioning is in use. 12 version, scheme = self.determine_version(request, *args, **kwargs) 13 request.version, request.versioning_scheme = version, scheme 14 15 # Ensure that the incoming request is permitted 16 self.perform_authentication(request) 開始認證 17 self.check_permissions(request) 18 self.check_throttles(request)
在request中做認證:
1 def _authenticate(self): 2 """ 3 Attempt to authenticate the request using each authentication instance 4 in turn. 5 """ 6 for authenticator in self.authenticators: 7 try: 8 user_auth_tuple = authenticator.authenticate(self) 9 except exceptions.APIException: 10 self._not_authenticated() 11 raise 12 13 if user_auth_tuple is not None: 14 self._authenticator = authenticator 15 self.user, self.auth = user_auth_tuple 16 return 17 18 self._not_authenticated()