zoukankan      html  css  js  c++  java
  • DRF之权限源码详解

    DRF之权限执行流程

    1.源码分析

    • 首先客户端所有的请求到来之后都会执行dispatch()方法,dispatch()方法会根据不同的请求方式,从而触发不同的方法,如GET/POST/PUT/DELETE/UPDATE等方法.
    #先进入dispatch方法
    class APIView(View):
        	...
            def dispatch(self, request, *args, **kwargs):
            self.args = args
            self.kwargs = kwargs
            
            #这里对Django的request做了进一步的封装
            request = self.initialize_request(request, *args, **kwargs)
            self.request = request
            self.headers = self.default_response_headers 
            try:
                
                # initial 处理版权信息,认证,权限,请求用户进行访问频率的限制  
                self.initial(request, *args, **kwargs)
                
                #点击进入initial
                ↓
        def initial(self, request, *args, **kwargs):
            self.format_kwarg = self.get_format_suffix(**kwargs)
            neg = self.perform_content_negotiation(request)
            request.accepted_renderer, request.accepted_media_type = neg
            version, scheme = self.determine_version(request, *args, **kwargs)
            request.version, request.versioning_scheme = version, scheme
            self.perform_authentication(request)  #用户认证
            self.check_permissions(request)  #这里做了用户权限设置
            
            #点击进入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)
                    )
    
        def check_object_permissions(self, request, obj):
            #用户对象级别的权限
            """
            Check if the request should be permitted for a given object.
            Raises an appropriate exception if the request is not permitted.
            """
            for permission in self.get_permissions():
                if not permission.has_object_permission(request, self, obj):
                    self.permission_denied(
                        request, message=getattr(permission, 'message', None)
                    )
                    #点击进入get_permissions()
                       ↓
        def get_permissions(self):
            #这里返回了一个权限的对象列表
            return [permission() for permission in self.permission_classes]
        				↓
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES #所以可以使用全局配置 
    					#进入api_settings
        				↓
    
    REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES':['api.utils.permission.MyPermission',...]
    } #全局默认使用 Mypermission 上面是 文件路径 不想用的就重写 
    
    #回到check_permission 方法
        def check_permissions(self, request):
            for permission in self.get_permissions():
                if not permission.has_permission(request, self):  #如果 has_permission返回false则权限不通过,否则通过
                    self.permission_denied(
                        request, message=getattr(permission, 'message', None)
                    ) #message是提示错误的信息
    								↓
        def permission_denied(self, request, message=None):
            if request.authenticators and not request.successful_authenticator:
                raise exceptions.NotAuthenticated()  #报错
            raise exceptions.PermissionDenied(detail=message)
    

    2.代码实现

    #新建permission.py文件
    from rest_framework.authentication import BaseAuthentication, exceptions
    from rest_framework.permissions import BasePermission
    from app import models
    
    class SVIPPermission(BasePremission):  #需继承BasePermission
        message = '级别不够,无法访问'
        def has_permission(self, request, view):  #重写这个方法 对应源码,返回false就是不通过
            if request.user.user_type != 3:
                return False
            return True
    
    class MyPermission(BasePremission):
        def has_permission(self, request, view):
            if request.user.user_type == 3:
                return False
            return True
    
        
    #在view视图函数中
    class OrderView(APIView):
        '''
        订单业务svip
        '''
        permission_classes = [SVIPPermission,]  #自己写了用自己的
        def get(self, request, *args, **kwargs):
            ret = {'code': 1000, 'msg': None}
            try:
                ret['data'] = ORDER_DICT
            except Exception as e:
                pass
            return JsonResponse(ret)
    
    
    class UserInfoView(Base):  #什么也没有写 默认是全局的权限设置类
        '''
        订单业务普通用户
        '''
        def get(self, *args, **kwargs):
            return HttpResponse('用户信息')
    
    

    3.全局配置

    REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES':['api.utils.permission.MyPermission',...]
    } #全局默认使用 Mypermission 上面是 文件路径 不想用的就重写 
    

    4.代码规范

    #和用户认证相同  权限类也都应该依据代码规范继承BasePermission
    from rest_framework.permissions import BasePermission
    class MyPermission(BasePermission):
        pass
    
    #BasePermission源码
    class BasePermission(metaclass=BasePermissionMetaclass):
    
        def has_permission(self, request, view):
            return True
    
        def has_object_permission(self, request, view, obj): #对某个对象是否有权限 力度更细
            return True
    

    5.has_object_permission

    • 我们在写权限一般只用has_permission 但其实是有两个方法来控制权限的,另一个是has_object_permission,它的具体作用是:对某个对象是否有权限 粒度更细
    • 分析:
    #主要是在GenericAPIView中
    GenericAPIView.get_object  #只有调用这类的get_object这个方法  才必须有has_object_permission方法
    	check_object_permission
        has_object_permission
    
  • 相关阅读:
    全志A10_linux3.0内核编译记录
    C#使用Socket登陆WordPress源码
    UIKeyboardType键盘
    浅谈 iOS 版本号
    学习软件开发应该看的书
    NSPredicate的用法
    ios 技巧总结(不断更新)
    RSA 加解密
    GCD下的几种实现同步的方式
    iOS事件处理
  • 原文地址:https://www.cnblogs.com/maqian/p/12957636.html
Copyright © 2011-2022 走看看