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
原文地址:https://www.cnblogs.com/maqian/p/12957636.html