zoukankan      html  css  js  c++  java
  • 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()
  • 相关阅读:
    appdata文件夹有什么用途?C盘appdata可以删除吗?
    白话讲MyIsam和InnoDB的区别
    MVC&&MVP
    计算机程序的思维逻辑- 函数调用的基本原理
    猫狗收养所
    博客学习分类
    Android之操作SQLite
    总结---20160508
    对栈元素排序
    集合栈
  • 原文地址:https://www.cnblogs.com/arrow-kejin/p/9986713.html
Copyright © 2011-2022 走看看