restframework 权限流程 及自定义权限类

一.请求来到之后,都要先执行dispatch方法

 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进行加工(添加数据)
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        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

            # 第三步、执行:get/post/put/delete函数
            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

二.下面我们直接分析第二步

1.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.
        #2.1 处理版本信息
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

        # Ensure that the incoming request is permitted
        #2.2 认证
        self.perform_authentication(request)
        # 2.3 权限
        self.check_permissions(request)
        # 2.4 请求用户进行访问频率的限制
        self.check_throttles(request)

2.self.check_permissions(request)具体干了什么

def check_permissions(self, request):
        # 遍历权限对象列表得到一个个权限对象(权限器),进行权限认证
        for permission in self.get_permissions():
            # 权限类一定有一个has_permission权限方法,用来做权限认证的
            # 参数:权限对象self、请求对象request、视图类对象
            # 返回值:有权限返回True,无权限返回False
            if not permission.has_permission(request, self):
                self.permission_denied(
                    request, message=getattr(permission, 'message', None)
                )

3.其中循环遍历了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]

4.进去后发现了一个熟悉的self.permission_classes 是api_settings中的系统权限类

    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ],

 5.这四个系统权限类,我们他们具体看看做了些什么

"""
1)AllowAny:
    认证规则全部返还True:return True
        游客与登陆用户都有所有权限

2) IsAuthenticated:
    认证规则必须有登陆的合法用户:return bool(request.user and request.user.is_authenticated)
        游客没有任何权限,登陆用户才有权限
    
3) IsAdminUser:
    认证规则必须是后台管理用户:return bool(request.user and request.user.is_staff)
        游客没有任何权限,登陆用户才有权限

4) IsAuthenticatedOrReadOnly
    认证规则必须是只读请求或是合法用户:
        return bool(
            request.method in SAFE_METHODS or
            request.user and
            request.user.is_authenticated
        )
        游客只读,合法用户无限制
"""

6.分析以上四个系统权限类,他们返回值都是bool值  都是判断各自的想要实现的认证规则,因此我们也可以模仿他们写一个这样的自定义权限类

自定义权限类

全局配置:settings.py

REST_FRAMEWORK = {
    # 权限类配置
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ],
}  

这是全局配置,而且其中是AllowAny 游客和登录用户都有所有权限  因此 我们可以配置局部配置

局部配置 :views.py

# api/views.py
from rest_framework.permissions import IsAuthenticated
class TestAuthenticatedAPIView(APIView):
    permission_classes = [IsAuthenticated]
    def get(self, request, *args, **kwargs):
        return APIResponse(0, 'test 登录才能访问的接口 ok')

自定义权限类

"""
1) 创建继承BasePermission的权限类
2) 实现has_permission方法
3) 实现体根据权限规则 确定有无权限
4) 进行全局或局部配置

认证规则
i.满足设置的用户条件,代表有权限,返回True
ii.不满足设置的用户条件,代表有权限,返回False
"""
# utils/permissions.py
from rest_framework.permissions import BasePermission
from django.contrib.auth.models import Group
class MyPermission(BasePermission):
    def has_permission(self, request, view):
        # 只读接口判断
        r1 = request.method in ('GET', 'HEAD', 'OPTIONS')
        # group为有权限的分组
        group = Group.objects.filter(name='管理员').first()
        # groups为当前用户所属的所有分组
        groups = request.user.groups.all()
        r2 = group and groups
        r3 = group in groups
        # 读接口大家都有权限,写接口必须为指定分组下的登陆用户
        return r1 or (r2 and r3)
    
    

#views.py
# 游客只读,登录用户只读,只有登录用户属于 管理员 分组,才可以增删改
from utils.permissions import MyPermission
class TestAdminOrReadOnlyAPIView(APIView):
    permission_classes = [MyPermission]
    # 所有用户都可以访问
    def get(self, request, *args, **kwargs):
        return APIResponse(0, '自定义读 OK')
    # 必须是 自定义“管理员”分组 下的用户
    def post(self, request, *args, **kwargs):
        return APIResponse(0, '自定义写 OK')
万般皆下品,唯有读书高!
原文地址:https://www.cnblogs.com/s686zhou/p/11721214.html