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‘],
}

原文地址:https://www.cnblogs.com/yyyyyyyyyy/p/9502014.html

时间: 2024-10-11 00:24:18

Django REST framework —— 权限组件源码分析的相关文章

Django rest framework 权限操作(源码分析二)

知识回顾 这一篇是基于上一篇写的,上一篇谢了认证的具体流程,看懂了上一篇这一篇才能看懂, 当用户访问是 首先执行dispatch函数,当执行当第二部时: #2.处理版本信息 处理认证信息 处理权限信息 对用户的访问频率进行限制 self.initial(request, *args, **kwargs) 进入到initial方法: def initial(self, request, *args, **kwargs): """ Runs anything that needs

django的RBAC认证z;自定义auth_user表;认证组件权限组件源码分析;认证组件;权限组件

一 RBAC 1.RBAC:全称(Role-Based Access Control):指的是基于用户权限访问控制的认证. 2.Django框架采用的是RBAC认证规则,RBAC认证规则通常会分为:三表规则,五表规则:Django采用的是六表规则. # 三表:用户表.角色表.权限表# 五表:用户表.角色表.权限表.用户角色关系表.角色权限关系表# 六表:用户表.角色表.权限表.用户角色关系表.角色权限关系表.用户权限关系表 3.在Django中六表之间是都是多对多的关系,可通过下面字段跨表访问

Django的settings文件部分源码分析

Django的settings文件部分源码分析 在编写Django项目的过程中, 其中一个非常强大的功能就是我们可以在settings文件配置许多选项来完成我们预期的功能, 并且这些配置还必须大写, 否则就不会生效. 此外, Django自身还有一套更详细的配置, 那Django是如何做到用户配置了相关配置就使用用户的配置, 否则就使用自己默认的配置. 带着这样的疑问, 去查看了用户配置项相关的源码部分. 过程分析 首先启动Django项目, 一般Django都是通过python manage.

Django——基于类的视图源码分析 二

源码分析 抽象类和常用视图(base.py) 这个文件包含视图的顶级抽象类(View),基于模板的工具类(TemplateResponseMixin),模板视图(TemplateView)和重定向视图(RedirectView). View及View的执行顺序 View是所有基于类的视图的基类.仅实现了一些基本的方法和必要的检查工作.其中最重要的是dispatch方法.再次方法中,根据HTTP请求 中的method参数,调用相应的同名处理函数.这里留下了一个口子,后续的类需要根据自己的情况来填补

Django的rest_framework的权限组件和频率组件源码分析

前言: Django的rest_framework一共有三大组件,分别为认证组件perform_authentication,权限组件check_throttles: 我在前面的博客中已经梳理了认证组件,不知道大家有没有看懂:在这里我把认证的组件的博客地址在贴出来,不清楚的人可以看下 局部设置认证组件的博客:https://www.cnblogs.com/bainianminguo/p/10480887.html 全局设置认证组件的博客:https://www.cnblogs.com/baini

Django的rest_framework的分页组件源码分析

前言: 分页大家应该都很清楚,今天我来给大家做一下Django的rest_framework的分页组件的分析:我的讲解的思路是这样的,分别使用APIview的视图类和基于ModelViewSet的视图类两种方式实现分页的功能,同时我也会介绍两个分页的类,PageNumberPagination类和LimitOffsetPagination,希望能对大家有所帮助! 今天的博客主要的这样的,先讲解基于APIView类的两种分页类的实现方式,然后在讲解基于ModelViewSet类的两种分页类的实现方

Spring MVC组件源码分析

组件概览 HandlerMapping 根据 request 找到对应的处理器 Handler 和 Interceptors.内部只有一个方法 HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; HandlerAdapter Handler 适配器,内部方法如下: boolean supports(Object handler);//判断是否可以使用某个 Handler ModelAndVi

Django——基于类的视图源码分析 一

基于类的视图(Class-based view)是Django 1.3引入的新的视图编写方式,用于取代以前基于函数(Function-based)方式. 借助于OO和Python中方便的多重继承特性,基于类的视图可以提供更好的抽象与复用能力. 新的通用视图将更加优雅. Django的文档较为丰富,但在实际开发中往往仍显得不够,很多时候还是需要深入到源代码当中一探究竟.为此,仔细整理了一下基于类的视图的实现方式.期望对以后的开发能够提供更加清晰.直接的参考. 说明: Django大量应用了多重继承

Django Signals 从实践到源码分析(转)

原文:http://foofish.net/blog/66/django-signals 当某个事件发生的时候,signal(信号)允许senders(发送者)用来通知receivers(接收者),通知receivers干嘛?你想要recivers干嘛就可以干嘛.这在多处代码 对同一个事件感兴趣的时候就有用武之地了. 比如:Django提供了一个built-in signal,叫django.core.signals.request_finished,这个signal会在一个 HTTP请求完成后