美文网首页
python rest framework 实现api的认证

python rest framework 实现api的认证

作者: 林木酸瓜 | 来源:发表于2019-06-19 22:15 被阅读0次

    一、认证的流程

    1. 首先我们采用的cbv的模式去写。去看以下加工后的request里面包含了什么?
    from django.shortcuts import HttpResponse
    from rest_framework.views import APIView
    
    class DogView(APIView):
    
        def get(self, request, *args, **kwargs):
            return HttpResponse('获取狗!')
    
        def post(self, request, *args, **kwargs):
            return HttpResponse('更新狗')
    

    其实APIView继承的是Django的View,只不过又在此基础上又丰富了一些。那么现在带大家来看一下源码!
    基于CBV的写法,那么当我们访问接口url的时候,那么首先执行的是dispath方法。

        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)
    
            # request._request 获取原生request
            # request.authenticators 获取认证类的对象
            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:
                    # 此处利用了Python的反射函数
                    handler = getattr(self, request.method.lower(),
                                      self.http_method_not_allowed)
                else:
                    handler = self.http_method_not_allowed
    
                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
    

    其中有一行是对原生的request进行加工,那么initialize_request函数又做了什么?

        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(),
                authenticators=self.get_authenticators(),
                negotiator=self.get_content_negotiator(),
                parser_context=parser_context
            )
    

    其中request是原始的request,今天的主角来了,就是authenticators。那么它又调用了get_authenticators(),

        def get_authenticators(self):
            """
            Instantiates and returns the list of authenticators that this view can use.
            """
            # 使用了列表生成式,那么我们得到的是一个 对象的list。
            return [auth() for auth in self.authentication_classes]
    

    那么self.authentication_classes 又是什么呢?

    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    

    从代码可知,这是django的配置文件里提供的DEFAULT_AUTHENTICATION_CLASSES

    那么现在我们已经知道: request里已经包含了最初的request(request._request), 以及认证后的对象[], (request.authenticators)

    1. 接下来到了try语句里面:
      self.initial(request, *args, **kwargs)
        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.
            version, scheme = self.determine_version(request, *args, **kwargs)
            request.version, request.versioning_scheme = version, scheme
    
            # Ensure that the incoming request is permitted
    
            # 主要看下面这一句 !!! 看这,来看下边!
            # 主要看下面这一句 !!! 看这,来看下边!
            self.perform_authentication(request)
            self.check_permissions(request)
            self.check_throttles(request)
    
        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, 因为带装饰符,所以以属性的方法调用,而此时self指的是Request的实例,

        @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
    

    此时又调用了_authenticate方法

        def _authenticate(self):
            """
            Attempt to authenticate the request using each authentication instance
            in turn.
            """
            for authenticator in self.authenticators:
                try:
                    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
                    return
    
            self._not_authenticated()
    

    各位同学,还记得authenticators这个么? 这个就是认证对象的list,那么从代码可知,我们的这个对象包含一个authenticate方法,所以所以所以我们自己定义的时候,就主要是定义这个方法!
    哇喔!!! 整体步骤我们理清了,那么如何来完成一个只有登录之后才可以访问的接口api呢。

    二、实现

    self.authentication_classes 当我们类提供authentication_classes这个属性时,那么就不会读取配置文件默认的。
    再来看以下代码:

    from rest_framework.views import APIView
    from rest_framework.authentication import BasicAuthentication
    from rest_framework import exceptions
    
    
    class MyAuthentication(object):
        def authenticate(self, request):
            token = request._request.GET.get('token')
            if not token:
                raise exceptions.AuthenticationFailed('用户认证失败')
            return ('alex', None)
    
        def authenticate_header(self, val):
            pass
    
    
    class DogView(APIView):
        authentication_classes = [MyAuthentication, ]
    
        def get(self, request, *args, **kwargs):
            return HttpResponse('获取狗!')
    
        def post(self, request, *args, **kwargs):
            return HttpResponse('更新狗')
    
    

    现在明白怎么回事了么? MyAuthentication类里面的authenticate_header这个函数虽然是空的代码,但是是强制要写的~ 至于为什么, tell me why?

    欢迎大家一起找我探讨Python的代码,前一段时间因为公司实在是太忙了,所以更新不太及时,各位请见谅~~~~~

    相关文章

      网友评论

          本文标题:python rest framework 实现api的认证

          本文链接:https://www.haomeiwen.com/subject/ytblqctx.html