zoukankan      html  css  js  c++  java
  • Django框架(二十)-- Django rest_framework-权限组件

    一、权限组件的使用

    # 用户信息表
    class UserInfo(models.Model):
        name = models.CharField(max_length=32)
        # 写choice
        user_choice=((0,'普通用户'),(1,'会员'),(2,'超级用户'))
        # 指定choice,可以快速的通过数字,取出文字
        user_type=models.IntegerField(choices=user_choice,default=0)
        pwd = models.CharField(max_length=32)
    
    # 用户token
    class UserToken(models.Model):
        token = models.CharField(max_length=64)
        user = models.OneToOneField(to=UserInfo)

    1、使用语法

    from rest_framework.permissions import BasePermission
    
    # 写一个权限类
    class UserPermission(BasePermission):
        # 重写没有权限时的数据
        message = '您没有权限'
        # 重写has_permission()方法,传入三个参数
        # 第一个是对象自身(自动传);第二个是request对象;第三个是
        def has_permission(self, request, view):
            # 只要认证通过,就会把当前用户对象放到request中
            user_type = request.user.user_type
            # get_字段名_display() 可以获取choice数字对应的具体值
            # user_type_name = request.user.get_user_type_display()
            # print(user_type_name)
            if user_type == 2:
                return True
            return Fals
    class Book(APIView):
        # 用户认证
        authentication_classes = [UserAuth.UserAuth, ]
        # 权限判断
        permission_classes = [MyPerm.UserPermission, ]
    
        def get(self, request, *args, **kwargs):
            response = {'status': 100, 'msg': '查询成功'}
            ret = models.Book.objects.all()
            ser = MySerializer.BookSerializer(instance=ret, many=True)
            response['data'] = ser.data
            return JsonResponse(response, safe=False)

    2、全局使用、局部使用、局部禁用权限

    (1)全局使用

    • 在settings文件中配置,配置完以后,就无需在视图类中写,已经是所有视图类都需要权限判断
    • 必须为REST_FRAMEWORK,key值必须为DEFAULT_AUTHENTICATION_CLASSES
    REST_FRAMEWORK={
        'DEFAULT_PERMISSION_CLASSES':['app01.MyPerm.UserPermission',],
    }

    (2)局部使用

    在需要使用的视图类中写,只对当前视图类起认证作用,重新定义permission_classes

    class Book(APIView):
        # # 该方法是局部使用认证
        authentication_classes = [UserAuth.UserAuth, ]
        # 该方法是局部使用权限
        permission_classes = [MyPerm.UserPermission, ]
    
        def get(self, request, *args, **kwargs):
            response = {'status': 100, 'msg': '查询成功'}
            ret = models.Book.objects.all()
            ser = MySerializer.BookSerializer(instance=ret, many=True)
            response['data'] = ser.data
            return JsonResponse(response, safe=False)

    (3)局部禁用

    在配置过全局权限判断以后,有些视图类不需要判断权限,可以局部禁用权限证,只需将permission_classes定义为空列表即可。

    class Book(APIView):
        # # 该方法是局部使用认证
        authentication_classes = [UserAuth.UserAuth, ]
        # 该方法是局部禁用权限
        permission_classes = []
    
        def get(self, request, *args, **kwargs):
            response = {'status': 100, 'msg': '查询成功'}
            ret = models.Book.objects.all()
            ser = MySerializer.BookSerializer(instance=ret, many=True)
            response['data'] = ser.data
            return JsonResponse(response, safe=False)

    二、源码分析

    as_view ----------> view -------------> dispatch -------> Request包装新的request ------> 认证、权限、频率 --------> 根据请求方式分发到不同的方法

    1、Book中没有as_view

    2、APIView的as_view

    class APIView(View):
        
        @classmethod
        # cls 是 Book类
        def as_view(cls, **initkwargs):
                
            # view = super(APIView, Book).as_view(**initkwargs)
            view = super(APIView, cls).as_view(**initkwargs)
            view.cls = cls
            view.initkwargs = initkwargs
    
            # Note: session based authentication is explicitly CSRF validated,
            # all other authentication is CSRF exempt.
            return csrf_exempt(view)

    3、view = super(APIView, cls).as_view(**initkwargs) ---------------------> View中的as_view

    class View(object):
        
        @classonlymethod
        # cls====> Book
        def as_view(cls, **initkwargs):
    
            def view(request, *args, **kwargs):
                # 实例化产生一个book对象
                self = cls(**initkwargs)
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
                self.request = request
                self.args = args
                self.kwargs = kwargs
                # 调dispatch方法
                return self.dispatch(request, *args, **kwargs)
            view.view_class = cls
            view.view_initkwargs = initkwargs
    
            # take name and docstring from class
            update_wrapper(view, cls, updated=())
    
            # and possible attributes set by decorators
            # like csrf_exempt from dispatch
            update_wrapper(view, cls.dispatch, assigned=())
            return view

    4、return self.dispatch(request, *args, **kwargs) ----------------> dispatch

    self====> Book对象,一层层找dispatch

    APIView中找到dispatch

    class APIView(View):
        
        def dispatch(self, request, *args, **kwargs):
    
            self.args = args
            self.kwargs = kwargs
            
            # (a)初始化request,就是通过Request类来包装原生request,得到包装后的request
            request = self.initialize_request(request, *args, **kwargs)
            # 从现在开始request就是包装后的request
            self.request = request
            self.headers = self.default_response_headers  # deprecate?
    
            try:
                # (b) 认证、权限、频率
                self.initial(request, *args, **kwargs)
    
                # Get the appropriate handler method
                # http_method_names表示列表['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
                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
        

    (a)request = self.initialize_request(request, *args, **kwargs) 包装 request

    self 是Book对象

    class APIView(View):
        # 默认的认证列表类
        authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
        def initialize_request(self, request, *args, **kwargs):
            """
            Returns the initial request object.
            """
            parser_context = self.get_parser_context(request)
            # (a-b)实例化初始化产生新的request对象
            return Request(
                request,
                parsers=self.get_parsers(),
                authenticators=self.get_authenticators(),  # 认证类实例化产生的对象的列表
                negotiator=self.get_content_negotiator(),
                parser_context=parser_context
            )
        def get_authenticators(self):
            """
            Instantiates and returns the list of authenticators that this view can use.
            """
            return [auth() for auth in self.authentication_classes]
    (a------1)return Request( ··· ) ----------> Request类初始化
        def __init__(self, request, parsers=None, authenticators=None,
                     negotiator=None, parser_context=None):
            assert isinstance(request, HttpRequest), (
                'The `request` argument must be an instance of '
                '`django.http.HttpRequest`, not `{}.{}`.'
                .format(request.__class__.__module__, request.__class__.__name__)
            )
    
            self._request = request
            self.parsers = parsers or ()
            self.authenticators = authenticators or ()
            self.negotiator = negotiator or self._default_negotiator()
            self.parser_context = parser_context
            self._data = Empty
            self._files = Empty
            self._full_data = Empty
            self._content_type = Empty
            self._stream = Empty
    
            if self.parser_context is None:
                self.parser_context = {}
            self.parser_context['request'] = self
            self.parser_context['encoding'] = request.encoding or settings.DEFAULT_CHARSET
    
            force_user = getattr(request, '_force_auth_user', None)
            force_token = getattr(request, '_force_auth_token', None)
            if force_user is not None or force_token is not None:
                forced_auth = ForcedAuthentication(force_user, force_token)
                self.authenticators = (forced_auth,)

    (b)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
            # (b------1) 认证
            self.perform_authentication(request)
            # (b------2)权限
            self.check_permissions(request)
            # 频率
            self.check_throttles(request)
    (b------1) 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.
            """
            # (b------1---------1) get_permissions 权限类对象组成的列表
            for permission in self.get_permissions():
                # 重写的就是这个has_permission()方法,判断当前用户是否有权限
                if not permission.has_permission(request, self):
                    self.permission_denied(
                        request, message=getattr(permission, 'message', None)
                    )
    (b------1---------1) 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]
  • 相关阅读:
    CF1208C
    CF1208B
    CF1208A
    CF1206A
    wqy的C题
    wqy的B题
    [POI2005]SAM-Toy Cars
    Gym
    操作系统学习---进程
    C++多线程(POSIX)
  • 原文地址:https://www.cnblogs.com/zhangbingsheng/p/10720971.html
Copyright © 2011-2022 走看看