DRF之权限组件源码分析

发布时间 2023-09-18 22:14:41作者: Chimengmeng

【一】权限组件介绍

  • Django REST framework(DRF)中的权限组件用于控制API的访问权限。
  • DRF内置了多个常用的权限类,同时也允许你创建自定义的权限类以满足特定需求。

【二】内置权限类

  • IsAuthenticated:要求用户在访问API时进行身份验证,即用户必须登录。
  • IsAdminUser:要求用户是管理员。
  • IsAuthenticatedOrReadOnly:要求用户在写入数据(例如创建、更新、删除)之前进行身份验证,但允许未经身份验证的用户进行只读操作。
  • IsOwnerOrReadOnly:通常用于处理对象级别的权限。它要求用户在对对象进行写入操作时是对象的所有者,但允许未经身份验证的用户进行只读操作。

【三】执行流程分析

  • DRF的权限组件在视图类的 perform_authentication 方法之后执行。

image-20230918192622450

# 执行视图类中的 校验函数,也就是我们重写的has_permission 方法
# 完成对权限的校验 , 返回 True 或 False 供其他方法进一步判断
# 当返回True 时 ,可以返回一个 User 对象
self.check_permissions(request)
  • 用户发送API请求。

image-20230918192702602

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():
        
        # 判断权限类中是否重写了 has_permission 校验方法
        # 如果没有重写则抛出异常
        if not permission.has_permission(request, self):
            self.permission_denied(
                request,
                message=getattr(permission, 'message', None),
                code=getattr(permission, 'code', None)
            )
  • DRF的身份验证组件(如Token、Session等)会验证用户的身份,并将用户信息添加到请求对象中。

image-20230918192728165

  • 权限组件开始执行。
    • 它会检查请求对象中的用户信息,并根据所选的权限类来判断用户是否有权限访问视图。
def get_permissions(self):
    """
        Instantiates and returns the list of permissions that this view requires.
        """
    # 将每一个权限类对象返回给上层调用
    return [permission() for permission in self.permission_classes]
  • 如果权限验证失败,DRF将返回HTTP 403 Forbidden响应。

【四】内置权限类源码分析

【0】BasePermission

  • BasePermission 类是所有自定义权限类的基类。
  • 它定义了 has_permissionhas_object_permission 两个方法,这些方法用于控制API的访问权限。
from rest_framework.permissions import BasePermission
class BasePermission(metaclass=BasePermissionMetaclass):
    """
    A base class from which all permission classes should inherit.
    """
	
    # 视图级别的权限检查,它接受 request 和 view 参数,
    # 在这个方法中编写自定义的权限逻辑来判断用户是否有权访问整个视图。
    def has_permission(self, request, view):
        """
        Return `True` if permission is granted, `False` otherwise.
        """
        return True
	
    # 对象级别的权限检查,它接受 request、view 和 obj 参数
    # 在这个方法中编写自定义的权限逻辑来判断用户是否有权访问特定对象(例如数据库中的某个记录)。
    def has_object_permission(self, request, view, obj):
        """
        Return `True` if permission is granted, `False` otherwise.
        """
        return True

【1】IsAuthenticated

  • 要求用户在访问API时进行身份验证,即用户必须登录。
from rest_framework.permissions import IsAuthenticated
class IsAuthenticated(BasePermission):
    """
    Allows access only to authenticated users.
    """

    def has_permission(self, request, view):
        return bool(request.user and request.user.is_authenticated)

【2】IsAdminUser

  • 要求用户是管理员。
from rest_framework.permissions import IsAdminUser
class IsAdminUser(BasePermission):
    """
    Allows access only to admin users.
    """

    def has_permission(self, request, view):
        return bool(request.user and request.user.is_staff)

【3】IsAuthenticatedOrReadOnly

  • 要求用户在写入数据(例如创建、更新、删除)之前进行身份验证,但允许未经身份验证的用户进行只读操作。
from rest_framework.permissions import  IsAuthenticatedOrReadOnly
class IsAuthenticatedOrReadOnly(BasePermission):
    """
    The request is authenticated as a user, or is a read-only request.
    """

    def has_permission(self, request, view):
        return bool(
            request.method in SAFE_METHODS or
            request.user and
            request.user.is_authenticated
        )

【4】IsOwnerOrReadOnly

  • 通常用于处理对象级别的权限。它要求用户在对对象进行写入操作时是对象的所有者,但允许未经身份验证的用户进行只读操作。

【五】权限组件使用步骤(固定用法)

【1】创建权限认证类

  • 创建一个自定义的权限认证类,并让它继承自BasePermission

【2】实现has_permission方法

  • 在这个方法中编写自定义的权限逻辑来判断用户是否有权访问整个视图。

  • 在类中写方法:has_permission

    • 如果有权限,就返回True
    • 如果没有权限,就返回False
    • 错误信息是self.message='字符串'

【3】权限认证逻辑

# -*-coding: Utf-8 -*-
# @File : permission .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/7/30
from rest_framework import permissions

class CustomPermission(permissions.BasePermission):
    def has_permission(self, request, view):
        # 在这里编写视图级别的权限逻辑
        return True  # 或者根据需求返回 True 或 False

    def has_object_permission(self, request, view, obj):
        # 在这里编写对象级别的权限逻辑
        return True  # 或者根据需求返回 True 或 False

【4】使用权限认证类

  • 在视图类中,使用认证类

(1)局部使用

  • 在视图类中添加permission_classes属性,并将所需的权限认证类作为其值
  • 这样,在该视图类中只会应用指定的权限认证类。
# 权限认证
class UserDetailView(APIView):
    permission_classes = [AdminPermission, ]

(2)全局使用

  • 在配置文件(一般是settings.py)中进行全局配置,将权限认证类添加到DEFAULT_PERMISSION_CLASSES中。
  • 这样,在所有视图类中都会应用该权限认证类。
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'app01.permission.CustomPermission'
    ],
}

(3)全局使用/局部禁用

  • 当认证组件被全局配置后,可以在视图类中禁用全局认证组件,以实现局部禁用。
    • 如果权限认证组件被全局配置,你仍然可以在某个视图类中禁用全局的权限认证,实现局部禁用的效果。
    • 只需在该视图类中将permission_classes属性设置为空列表即可。
# 权限认证 - 局部禁用
class UserDetailView(APIView):
    permission_classes = []

(4)权限认证类的使用顺序

  • 先局部,在视图类定义的 permission_classes
  • 再全局,在DRF中自己配置的 DEFAULT_PERMISSION_CLASSES
  • 最后是,DRF默认配置中的 DEFAULT_PERMISSION_CLASSES