Source restful framework certification process

Source restful framework certification process

First, after a request comes, we have to perform the method dispatch, dispatch methods at the request of the different ways of triggering get / post / put / delete methods

Note, dispatch method APIView in with lots of features

Copy the code
    dispatch DEF (Self, Request, * args, ** kwargs): 
        "" " 
        ` .dispatch () `Pretty much at The Same, AS IS Django's Regular dispatch, 
        . But with Extra Hooks for the Startup, the Finalize, and Exception Handling 
        " "" 
        args = self.args 
        self.kwargs = kwargs Step: The request processing (addition data) 
        request self.initialize_request = (request, args *, ** kwargs) 
        self.request = request 
        self.headers # = self.default_response_headers deprecate? 
        the try: 
            # Step Two: 
                # handle copyright 
                # authentication 
                # permission 
                # restrict user access request frequency
        
 
            self.initial (request, * args, ** kwargs)

            The Get The Appropriate Handler Method # 
            IF request.method.lower () in self.http_method_names: 
                Handler = getattr (Self, request.method.lower (), 
                                  self.http_method_not_allowed) 
            the else: 
                Handler = self.http_method_not_allowed 

            # third step, performed : get / post / put / delete function of 
            the Response = Handler (Request, * args, ** kwargs) 

        the except Exception AS EXC: 
            the Response = self.handle_exception (EXC) # The fourth step is to return the results processed again  return self.response

        
        self.response = self.finalize_response(request, response, *args, **kwargs)
Copy the code

 

Second, the above is roughly step, we have to look at the following specific analysis, see each step was specifically done anything

1, a request processing (addition data)

We take a look request which those data are added

a, first request = self.initialize_request (request, * args, ** kwargs) into point will be found: in which pay more Request four, as follows

Copy the code
    initialize_request DEF (Self, Request, * args, ** kwargs): 
        "" " 
        . Returns at The Initial Request Object 
        " "" 
        # it ended up requesting a dictionary returns 
        parser_context = self.get_parser_context (Request) 

        return Request ( 
            Request, 
            parsers = self.get_parsers (), # parse the data, the default of three ways, you can go see point 
            # self.get_authenticator priority to find their own, not to find the father of 
            authenticators = self.get_authenticators (), # obtain all relevant certification examples of the class and the incoming request object Request for use 
            Negotiator = self.get_content_negotiator (), 
            parser_context = parser_context 
        )
Copy the code

b, authenticators like for specific authentication-related = self.get_authenticators (),

    def get_authenticators(self):
        """
        Instantiates and returns the list of authenticators that this view can use.
        """
        #返回的是对象列表
        return [auth() for auth in self.authentication_classes]  #[SessionAuthentication,BaseAuthentication]

c, view the certification class: self.authentication_classes

authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES # default, and if they have a preference for their own

d, then into api_settings

api_settings = APISettings (None, DEFAULTS, IMPORT_STRINGS) # Click inherited class DEFAULTS
= {DEFAULTS 
    # Base API Policies 
    'DEFAULT_AUTHENTICATION_CLASSES': ( 
        'rest_framework.authentication.SessionAuthentication', # this time found his default certificate class, you can import and see 
        'rest_framework.authentication.BasicAuthentication' 
    ),

e, introduced inside the class to see what specific class did

from rest_framework.authentication import SessionAuthentication
from rest_framework.authentication import BaseAuthentication

f, see authenticate method and which has a method authenticate_header

Copy the code
class BaseAuthentication(object):
    """
    All authentication classes should extend BaseAuthentication.
    """

    def authenticate(self, request):
        """
        Authenticate the request and return a two-tuple of (user, token).
        """
        raise NotImplementedError(".authenticate() must be overridden.")

    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.
        """
        pass
Copy the code

 Specific certification process, to obtain a user name and password from the headers inside

Copy the code
class BasicAuthentication(BaseAuthentication):
    """
    HTTP Basic authentication against username/password.
    """
    www_authenticate_realm = 'api'

    def authenticate(self, request):
        """
        Returns a `User` if a correct username and password have been supplied
        using HTTP Basic authentication.  Otherwise returns `None`.
        """
        auth = get_authorization_header(request).split()

        if not auth or auth[0].lower() != b'basic':
            return None   #返回none不处理。让下一个处理

        if len(auth) == 1:
            msg = _('Invalid basic header. No credentials provided.')
            raise exceptions.AuthenticationFailed(msg)
        elif len(auth) > 2:
            msg = _('Invalid basic header. Credentials string should not contain spaces.')
            raise exceptions.AuthenticationFailed(msg)

        try:
            auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':')   #用partition切割冒号也包括
        except (TypeError, UnicodeDecodeError, binascii.Error):
            msg = _('Invalid basic header. Credentials not correctly base64 encoded.')
            raise exceptions.AuthenticationFailed(msg)

        userid, password = auth_parts[0], auth_parts[2]  # 返回用户和密码
        return self.authenticate_credentials(userid, password, request)

    def authenticate_credentials(self, userid, password, request=None):
        """
        Authenticate the userid and password against username and password
        with optional request for context.
        """
        credentials = {
            get_user_model().USERNAME_FIELD: userid,
            'password': password
        }
        user = authenticate(request=request, **credentials)

        if user is None:
            raise exceptions.AuthenticationFailed(_('Invalid username/password.'))

        if not user.is_active:
            raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))

        return (user, None)

    def authenticate_header(self, request):
        return 'Basic realm="%s"' % self.www_authenticate_realm
Copy the code

g, of course, defined by default restfulframework two classes. We can also custom class, they have to use their own, and he did not went to the parent class, but there must implement the authenticate method, or will be error.

2, conduct some operations

  • Copyright information processing
  • Authenticate
  • Competence
  • Restrict user access request frequency

We mainly look at certification process

Certification process:

a, first of all self.initial (request, * args, ** kwargs) can be seen to do the following

Copy the code
    def initial(self, request, *args, **kwargs):
        """
        Runs anything that needs to occur prior to calling the method handler.
        """
        self.format_kwarg = self.get_format_suffix(**kwargs)

        # Perform content negotiation and store the accepted info on the request
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg

        # Determine the API version, if versioning is in use.
        #2.1 处理版本信息
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

        The incoming Request that Ensure® # IS permitted 
        # 2.2 certification 
        self.perform_authentication (Request) 
        # 2.3 permission 
        self.check_permissions (Request) 
        # 2.4 restrict user access request frequency 
        self.check_throttles (request)
Copy the code

 b, let's look at certification, self.perform_authentication (request) what specifically did, hold down ctrl click into

Copy the code
    def perform_authentication(self, request):
        """
        Perform authentication on the incoming request.

        Note that if you override this and simply 'pass', then authentication
        will instead be performed lazily, the first time either
        `request.user` or `request.auth` is accessed.
        """
        request.user   #执行request的user,这是的request已经是加工后的request了
Copy the code

c, then we can import it from view inside the Request, the user find the request object methods

from rest_framework.views import Request

Copy the code
    @property
    def user(self):
        """
        Returns the user associated with the current request, as authenticated
        by the authentication classes provided to the request.
        """
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():
                self._authenticate()  #
        return self._user  #返回user
Copy the code

d、执行self._authenticate() 开始用户认证,如果验证成功后返回元组: (用户,用户Token)

Copy the code
 def _authenticate(self):
        """
        Attempt to authenticate the request using each authentication instance
        in turn.
        """
        #循环对象列表
        for authenticator in self.authenticators:
            try:
                #执行每一个对象的authenticate 方法
                user_auth_tuple = authenticator.authenticate(self)   
            except exceptions.APIException:
                self._not_authenticated()
                raise

            if user_auth_tuple is not None:
                self._authenticator = authenticator
                self.user, self.auth = user_auth_tuple  #返回一个元组,user,和auth,赋给了self,
                # 只要实例化Request,就会有一个request对象,就可以request.user,request.auth了
                return

        self._not_authenticated() 
Copy the code

e、在user_auth_tuple = authenticator.authenticate(self) 进行验证,如果验证成功,执行类里的authenticatie方法 

f、如果用户没有认证成功:self._not_authenticated()

Copy the code
 def _not_authenticated(self):
        """
        Set authenticator, user & authtoken representing an unauthenticated request.

        Defaults are None, AnonymousUser & None.
        """
        #如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
        self._authenticator = None  #

        if api_settings.UNAUTHENTICATED_USER:
            self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户AnonymousUser
        else:
            self.user = None  # None 表示跳过该认证

        if api_settings.UNAUTHENTICATED_TOKEN:
            self.auth = api_settings.UNAUTHENTICATED_TOKEN()  # 默认值为:None
        else:
            self.auth = None

    # (user, token)
    # 表示验证通过并设置用户名和Token;
    # AuthenticationFailed异常
Copy the code

3、执行get/post/delete等方法

4、对返回结果在进行加工

 

一、请求到来之后,都要先执行dispatch方法,dispatch方法方法根据请求方式的不同触发get/post/put/delete等方法

注意,APIView中的dispatch方法有很多的功能

Copy the code
    def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django's regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        """
        self.args = args
        self.kwargs = kwargs
        第一步:对request进行加工(添加数据)
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            #第二步:
                #处理版权信息
                #认证
                #权限
                #请求用户进行访问频率的限制
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

            # 第三步、执行:get/post/put/delete函数
            response = handler(request, *args, **kwargs)

        except Exception as exc:
            response = self.handle_exception(exc)

        #第四步、 对返回结果再次进行加工
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
Copy the code

 

二、上面是大致步骤,下面我们来具体分析一下,看每个步骤中都具体干了什么事

1、对request进行加工(添加数据)

我们来看看request里面都添加了那些数据

a、首先  request = self.initialize_request(request, *args, **kwargs)点进去,会发现:在Request里面多加了四个,如下

Copy the code
    def initialize_request(self, request, *args, **kwargs):
        """
        Returns the initial request object.
        """
        #吧请求弄成一个字典返回了
        parser_context = self.get_parser_context(request)

        return Request(
            request,
            parsers=self.get_parsers(),  #解析数据,默认的有三种方式,可点进去看
            #self.get_authenticator优先找自己的,没有就找父类的
            authenticators=self.get_authenticators(), #获取认证相关的所有类并实例化,传入request对象供Request使用
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
Copy the code

b、获取认证相关的类的具体   authenticators=self.get_authenticators(),

    def get_authenticators(self):
        """
        Instantiates and returns the list of authenticators that this view can use.
        """
        #返回的是对象列表
        return [auth() for auth in self.authentication_classes]  #[SessionAuthentication,BaseAuthentication]

c、查看认证的类:self.authentication_classes

authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES  #默认的,如果自己有会优先执行自己的

d、接着走进api_settings

api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)  #点击继承的DEFAULTS类
DEFAULTS = {
    # Base API policies
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',   #这时候就找到了他默认认证的类了,可以导入看看
        'rest_framework.authentication.BasicAuthentication'
    ),

e、导入了类看看类里面具体干了什么

from rest_framework.authentication import SessionAuthentication
from rest_framework.authentication import BaseAuthentication

f、看到里面有个authenticate方法和authenticate_header方法

Copy the code
class BaseAuthentication(object):
    """
    All authentication classes should extend BaseAuthentication.
    """

    def authenticate(self, request):
        """
        Authenticate the request and return a two-tuple of (user, token).
        """
        raise NotImplementedError(".authenticate() must be overridden.")

    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.
        """
        pass
Copy the code

 具体处理认证,从headers里面能获取用户名和密码

Copy the code
class BasicAuthentication(BaseAuthentication):
    """
    HTTP Basic authentication against username/password.
    """
    www_authenticate_realm = 'api'

    def authenticate(self, request):
        """
        Returns a `User` if a correct username and password have been supplied
        using HTTP Basic authentication.  Otherwise returns `None`.
        """
        auth = get_authorization_header(request).split()

        if not auth or auth[0].lower() != b'basic':
            return None   #返回none不处理。让下一个处理

        if len(auth) == 1:
            msg = _('Invalid basic header. No credentials provided.')
            raise exceptions.AuthenticationFailed(msg)
        elif len(auth) > 2:
            msg = _('Invalid basic header. Credentials string should not contain spaces.')
            raise exceptions.AuthenticationFailed(msg)

        try:
            auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':')   #用partition切割冒号也包括
        except (TypeError, UnicodeDecodeError, binascii.Error):
            msg = _('Invalid basic header. Credentials not correctly base64 encoded.')
            raise exceptions.AuthenticationFailed(msg)

        userid, password = auth_parts[0], auth_parts[2]  # 返回用户和密码
        return self.authenticate_credentials(userid, password, request)

    def authenticate_credentials(self, userid, password, request=None):
        """
        Authenticate the userid and password against username and password
        with optional request for context.
        """
        credentials = {
            get_user_model().USERNAME_FIELD: userid,
            'password': password
        }
        user = authenticate(request=request, **credentials)

        if user is None:
            raise exceptions.AuthenticationFailed(_('Invalid username/password.'))

        if not user.is_active:
            raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))

        return (user, None)

    def authenticate_header(self, request):
        return 'Basic realm="%s"' % self.www_authenticate_realm
Copy the code

g、当然restfulframework默认定义了两个类。我们也可以自定制类,自己有就用自己的了,自己没有就去找父类的了,但是里面必须实现authenticate方法,不然会报错。

2、进行一下操作

  • 处理版权信息
  • 认证
  • 权限
  • 请求用户进行访问频率的限制

我们主要来看一下认证流程

认证流程:

a、首先 self.initial(request, *args, **kwargs)可以看到做了以下操作

Copy the code
    def initial(self, request, *args, **kwargs):
        """
        Runs anything that needs to occur prior to calling the method handler.
        """
        self.format_kwarg = self.get_format_suffix(**kwargs)

        # Perform content negotiation and store the accepted info on the request
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg

        # Determine the API version, if versioning is in use.
        #2.1 处理版本信息
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

        # Ensure that the incoming request is permitted
        #2.2 认证
        self.perform_authentication(request)
        # 2.3 权限
        self.check_permissions(request)
        # 2.4 请求用户进行访问频率的限制
        self.check_throttles(request)
Copy the code

 b、我们先来看认证,self.perform_authentication(request) 具体干了什么,按住ctrl点击进去

Copy the code
    def perform_authentication(self, request):
        """
        Perform authentication on the incoming request.

        Note that if you override this and simply 'pass', then authentication
        will instead be performed lazily, the first time either
        `request.user` or `request.auth` is accessed.
        """
        request.user   #执行request的user,这是的request已经是加工后的request了
Copy the code

c、那么我们可以从视图里面导入一下Request,找到request对象的user方法

from rest_framework.views import Request

Copy the code
    @property
    def user(self):
        """
        Returns the user associated with the current request, as authenticated
        by the authentication classes provided to the request.
        """
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():
                self._authenticate()  #
        return self._user  #返回user
Copy the code

d、执行self._authenticate() 开始用户认证,如果验证成功后返回元组: (用户,用户Token)

Copy the code
 def _authenticate(self):
        """
        Attempt to authenticate the request using each authentication instance
        in turn.
        """
        #循环对象列表
        for authenticator in self.authenticators:
            try:
                #执行每一个对象的authenticate 方法
                user_auth_tuple = authenticator.authenticate(self)   
            except exceptions.APIException:
                self._not_authenticated()
                raise

            if user_auth_tuple is not None:
                self._authenticator = authenticator
                self.user, self.auth = user_auth_tuple  #返回一个元组,user,和auth,赋给了self,
                # 只要实例化Request,就会有一个request对象,就可以request.user,request.auth了
                return

        self._not_authenticated() 
Copy the code

e、在user_auth_tuple = authenticator.authenticate(self) 进行验证,如果验证成功,执行类里的authenticatie方法 

f、如果用户没有认证成功:self._not_authenticated()

Copy the code
 def _not_authenticated(self):
        """
        Set authenticator, user & authtoken representing an unauthenticated request.

        Defaults are None, AnonymousUser & None.
        """
        #如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
        self._authenticator = None  #

        if api_settings.UNAUTHENTICATED_USER:
            self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户AnonymousUser
        else:
            self.user = None  # None 表示跳过该认证

        if api_settings.UNAUTHENTICATED_TOKEN:
            self.auth = api_settings.UNAUTHENTICATED_TOKEN()  # 默认值为:None
        else:
            self.auth = None

    # (user, token)
    # Denotes validated and set the username and Token; 
    # AuthenticationFailed abnormal
Copy the code

3, the implementation of get / post / delete methods

4, processing is performed to return results

 

Guess you like

Origin www.cnblogs.com/mqhpy/p/11388273.html