1. 程式人生 > >django rest framework_jwt之認證的原始碼流程剖析

django rest framework_jwt之認證的原始碼流程剖析

檢視程式碼

 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()