DRF-基于APIView的认证流程

  1. 云栖社区>
  2. 博客>
  3. 正文

DRF-基于APIView的认证流程

翁闻宇 2019-01-10 08:54:00 浏览1237
展开阅读全文

rest framework框架

  • 我们来看一段伪代码,MyClassView继承了APIView就有了APIView的功能
class APIView(View):
    pass 


class MyClassView(APIView):
    pass
  • 基于Django的CBV
from django.views import View
from django.http import HttpResponse


class MyClassView(View):
    def get(self, request, *args, **kwargs):
        ret = {
            "state_code": 1000,
            "msg": "successful"
        }
        import json
        return HttpResponse(json.dumps(ret), status=201)

    def post(self, request, *args, **kwargs):
        return HttpResponse("created successful")

    def delete(self, request, *args, **kwargs):
        return HttpResponse("delete successful")
  • 基于DRF的CBV ,DRF的APIView在Django的View基础上,增加和丰富了一些功能
from django.views import View
from django.http import HttpResponse
from rest_framework.views import APIView


class MyClassView(APIView):
    def get(self, request, *args, **kwargs):
        ret = {
            "state_code": 1000,
            "msg": "successful"
        }
        import json
        return HttpResponse(json.dumps(ret), status=201)

    def post(self, request, *args, **kwargs):
        return HttpResponse("created successful")

    def delete(self, request, *args, **kwargs):
        return HttpResponse("delete successful")

原理(流程)

  • 当请求进来,先找CBV里面的dispatch方法
"""
rest_framework\views.py 
"""

 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:
                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
  • 反射
img_dcba43f89f181da9026d8af423f89bdf.png
微信截图_20190108191829
  • request加强
img_80a8f7ff3d26b195d2d01e32a3466d23.png
微信截图_20190108200309
  • self.initialize_request方法做了什么?
img_c8c9107c6c022a2cb1d4304dd55575dd.png
微信截图_20190108200451

def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(request)

# 加工后新生成了Request对象
return Request(
    request,  # 原本的那个request
    parsers=self.get_parsers(),
    authenticators=self.get_authenticators(), # 认证相关
    negotiator=self.get_content_negotiator(),
    parser_context=parser_context
)
  • self.get_authenticators()方法
img_30b8b691e25bc112025174953a76dc57.png
微信截图_20190108201228
def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
# self.authentication_classes = [Dog,Cat]   auth()就是Dog和Cat对象,被装进列表里面 
return [auth() for auth in self.authentication_classes]
  • get_authenticators()方法中的self.authentication_classes,先从当前类找,有就使用当前类的authentication_classes,没有就使用父类的authentication_classes,在这里使用的是APIView里面的
img_73703e9f2a8544c3e6c421d23388a89e.png
微信截图_20190108201739
img_fe1828c471dc6144fe05dddcd90f366c.png
微信截图_20190108202231
  • 回到dispatch方法,我们可以看到其实request对象里面就有原生request和[BasicAuthentication,]
img_03eb3b96983e422cd3d0de8ddd17e15a.png
微信截图_20190108203020
  • 拿到原生request方法
img_a096e8417e4a67edcde8748ea8cb1e9d.png
微信截图_20190108203935
  • 获取认证类的对象,request.authenticators和原生request
img_a97cb0e284540a9a95c1232f7bd60299.png
微信截图_20190108204355
  • 我们可以查看dispatch方法里面的反射前做了是什么,self.initial方法
img_f4e11ecfcc5915717ecebf7765527a19.png
微信截图_20190108204819
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)
img_eb486d8c8da005f06f6879b117296f3a.png
微信截图_20190108205218
  • 父类的perform_authentication()方法
img_03a054c0548a988f40ee44cbf0797eaf.png
微信截图_20190108205348
img_2ab0ebc80afeec9718cbfcf1fbbf1ae6.png
微信截图_20190108205626
  • 找到user
img_f9d644a8cef6c1dda089b62893bdfdb6.png
微信截图_20190108205727
# _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()
img_0d12d5c0ea5bf99df0a4f714d5702e74.png
微信截图_20190108210210

登陆认证

  • 我们可以编写一个自己的认证类
class MyAuthentication(object):
    def authenticate(self, request):
        token = request._request.GET.get('token')
        if not token:
            from rest_framework import exceptions
            raise exceptions.AuthenticationFailed("对不起,用户认证失败")
        return ("zhangsan", None)

  • postman验证
img_90bbf795b63173c9d95f65fba51ab612.png
微信截图_20190108211046
img_bb1f2f6511b1a2b0c83623bac2119f33.png
微信截图_20190108211238
  • 解决报错
img_ab0d10e39391e26eae1ea15e3e7630f7.png
微信截图_20190108211347
  • postman验证
img_30c31c2ae5926746a5435f93aa0bf027.png
微信截图_20190108211418
  • 解决方案2
img_f9251be98d781a8619032e04dd176db0.png
微信截图_20190108211524
  • 以后我们比如有些API需要认证才能看,我们就可以在这里进行操作

DRF认证流程:

  • 请求进来先走dispatch方法
  1. dispatch方法里面封装了request
img_3dfff30f5e09ef94a33a8b50d77f2297.png
微信截图_20190108211939
  1. 调用initial
img_10e8c5e3b5ea5d486468a6814ed741a0.png
微信截图_20190108212123
  1. 调用perform_authentication()


    img_685680eb95869834146e45ab2cddbd53.png
    微信截图_20190108212249
  2. 取user方法

img_fdb575bd8a8b40f7e9f8a73f32d03d0f.png
微信截图_20190108212402
  1. user方法里面调用了认证对象
img_0b3c7d561198563997cb82b83de33321.png
微信截图_20190108212533
  1. 遍历认证
img_dadccbc8d32f7c1f67a2b1fe2c6074c9.png
微信截图_20190108212748

使用

img_426b76792052ec5a520d11fd2fb81b08.png
微信截图_20190108213110
img_1e9a135e89f7a1c41944f026b1175eb2.png
微信截图_20190108213327
img_7513ae81f1358f3e57c03aa024a1e000.png
微信截图_20190108213349

网友评论

登录后评论
0/500
评论
翁闻宇
+ 关注