zoukankan      html  css  js  c++  java
  • Django REST framework —— 权限组件源码分析

    在上一篇文章中我们已经分析了认证组件源码,我们再来看看权限组件的源码,权限组件相对容易,因为只需要返回True 和False即可

    代码

     1 class ShoppingCarView(ViewSetMixin, APIView):
     2      permission_classes = [MyPermission, ]
     3         def list(self,request, *args, **kwargs):
     4         """
     5         查看购物车信息
     6         :param args:
     7         :param kwargs:
     8         :return:
     9         """
    10         try:
    11             ret = BaseResponse()
    12             pay_course_list = []
    13             # key = 'shoppingcar_%s_%s' % (USERID, '*')
    14             key = settings.SHOPCAR_FORMAT.format( request.user.id, "*")
    15             user_key_list = COON.keys(pattern=key)  # 取到这个用户对应的所有课程字典 对应的键
    16             for key in user_key_list:
    17                 # 对应的每个键值 去取每个课程对应的信息 和价格列表
    18                 temp = {
    19                     'id': COON.hget(key, 'id').decode('utf8'),
    20                     'name': COON.hget(key, 'name').decode('utf8'),
    21                     'img': COON.hget(key, 'img').decode('utf8'),
    22                     'default': COON.hget(key, 'default').decode('utf8'),
    23                     'price_dict': json.loads(COON.hget(key, 'price_dict').decode('utf8')),
    24                 }
    25                 pay_course_list.append(temp)
    26             ret.data = pay_course_list
    27         except Exception as e:
    28             ret.data = '查看失败'
    29             ret.code = 00000
    30         return Response(ret.dict)
    31 
    32 视图类
    视图类
    class MyPermission(BasePermission):
        message = 'VIP用户才能访问'
    
        def has_permission(self, request, view):
            """
            自定义权限只有VIP用户才能访问
            """
            # 因为在进行权限判断之前已经做了认证判断,所以这里可以直接拿到request.user
            if request.user and request.user.type == 2:  # 如果是VIP用户
                return True
            else:
                return False
    自定义权限类
    urlpatterns = [
        url(r'^payment/$', payment.PaymentView.as_view({'post': 'create','put': 'update','get':'list'})),
    ]
    路由

    跟上一篇一样,来看代码是如何走到我自定义的权限类中的。

    1.首先从url中分析

      1.先来到视图类中的as.view()方法

      

      而我们的自定义的方法中没有as.view()方法,那就要去父类ViewSetMixin和APIView中去找,好看源码

    2.分析源码

      1.先看ViewSetMixin类中

        

        

    复制代码
    class ViewSetMixin(object):
        """
        This is the magic.
    
        Overrides `.as_view()` so that it takes an `actions` keyword that performs
        the binding of HTTP methods to actions on the Resource.
    
        For example, to create a concrete view binding the 'GET' and 'POST' methods
        to the 'list' and 'create' actions...
    
        view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
        """
    
        @classonlymethod
        def as_view(cls, actions=None, **initkwargs):
            """
            Because of the way class based views create a closure around the
            instantiated view, we need to totally reimplement `.as_view`,
            and slightly modify the view function that is created and returned.
            """
            # The suffix initkwarg is reserved for displaying the viewset type.
            # eg. 'List' or 'Instance'.
            cls.suffix = None
    
            # The detail initkwarg is reserved for introspecting the viewset type.
            cls.detail = None
    
            # Setting a basename allows a view to reverse its action urls. This
            # value is provided by the router through the initkwargs.
            cls.basename = None
    
            # actions must not be empty
            if not actions:
                raise TypeError("The `actions` argument must be provided when "
                                "calling `.as_view()` on a ViewSet. For example "
                                "`.as_view({'get': 'list'})`")
    
            # sanitize keyword arguments
            for key in initkwargs:
                if key in cls.http_method_names:
                    raise TypeError("You tried to pass in the %s method name as a "
                                    "keyword argument to %s(). Don't do that."
                                    % (key, cls.__name__))
                if not hasattr(cls, key):
                    raise TypeError("%s() received an invalid keyword %r" % (
                        cls.__name__, key))
    
            def view(request, *args, **kwargs):
                self = cls(**initkwargs)
                # We also store the mapping of request methods to actions,
                # so that we can later set the action attribute.
                # eg. `self.action = 'list'` on an incoming GET request.
                self.action_map = actions
    
                # Bind methods to actions
                # This is the bit that's different to a standard view
                for method, action in actions.items():
                    handler = getattr(self, action)
                    setattr(self, method, handler)
    
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
    
                self.request = request
                self.args = args
                self.kwargs = kwargs
    
                # And continue as usual
           # 前面都是在对传参做判断和重新赋值,重要的是下面这一步,最后return 调用了dispatch方法
    return self.dispatch(request, *args, **kwargs)
    复制代码

       2.找dispatch方法在哪里,答案肯定是在APIView中

      

    复制代码
     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 = self.initialize_request(request, *args, **kwargs)
         ## request = Request(.....) self.request = request self.headers = self.default_response_headers 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
    复制代码

        所有的关键点都在dispatch方法里面:

        (1)  request = self.initialize_request(request, *args, **kwargs) 

          

    复制代码
    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(),    #[BasicAuthentication(),],把对象封装到request里面了
           negotiator=self.get_content_negotiator(), parser_context=parser_context )

        (2) 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)

        (3)self.check_permissions(request) 

     def check_permissions(self, request):
            """
            Check if the request should be permitted.
            Raises an appropriate exception if the request is not permitted.
            """
            for permission in self.get_permissions():
                if not permission.has_permission(request, self):
                    self.permission_denied(
                        request, message=getattr(permission, 'message', None)
                    )

        (4)self.get_permissions():

        def get_permissions(self):
            """
            Instantiates and returns the list of permissions that this view requires.
            """
            return [permission() for permission in self.permission_classes]  列表生成式,把自定义的权限类的对象,放在一个对象中

        (5)self.permission_classes

        

        这里默认去settings全局中去找,如果局部配置了静态变量,就直接去找局部的静态变量

         (6)在看看我们继承的BasePermission

    class BasePermission(object):
        """
        A base class from which all permission classes should inherit.
        """
    
        def has_permission(self, request, view):
            """
            Return `True` if permission is granted, `False` otherwise.
            """
            return True
    
        def has_object_permission(self, request, view, obj):
            """
            Return `True` if permission is granted, `False` otherwise.
            """
            return True

     默认是没有任何逻辑判断的,所以我们在自定义权限类的时候,得自己写这两个方法。

     另外说明一下下面这个犯法的作用  

    def has_object_permission(self, request, view, obj):
            """
            Return `True` if permission is granted, `False` otherwise.
            """
            return True

     对当前登录用户做些判断

    def has_object_permission(self, request, view, obj):
        """
        判断当前评论用户的作者是不是你当前的用户
        只有评论的作者才能删除自己的评论
        """
          print('这是在自定义权限类中的has_object_permission')
          print(obj.id)
          if request.method in ['PUT', 'DELETE']:
              if obj.user == request.user:
                # 当前要删除的评论的作者就是当前登陆的用户
                  return True
              else:
                  return False
          else:
              return True

    总结:

    (1)使用

    • 自己写的权限类:1.必须继承BasePermission类;  2.必须实现:has_permission方法

    (2)返回值

    • True   有权访问
    • False  无权访问

    (3)局部

    • permission_classes = [MyPremission,] 

     (4)全局

    REST_FRAMEWORK = {
       #权限
        "DEFAULT_PERMISSION_CLASSES":['API.utils.permission.SVIPPremission'],
    }
  • 相关阅读:
    Java学习二十九天
    Java学习二十八天
    47. Permutations II 全排列可重复版本
    46. Permutations 全排列,无重复
    subset ii 子集 有重复元素
    339. Nested List Weight Sum 339.嵌套列表权重总和
    251. Flatten 2D Vector 平铺二维矩阵
    217. Contains Duplicate数组重复元素
    209. Minimum Size Subarray Sum 结果大于等于目标的最小长度数组
    438. Find All Anagrams in a String 查找字符串中的所有Anagrams
  • 原文地址:https://www.cnblogs.com/yyyyyyyyyy/p/9502014.html
Copyright © 2011-2022 走看看