美文网首页
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