DRF权限

DRF 的权限系统用于控制用户对 API 端点的访问权限,它在认证系统之后执行,决定已认证用户可以执行什么操作。

1、BasePermission

所有权限类都应从其继承的基类。


class BasePermission(metaclass=BasePermissionMetaclass):

    def has_permission(self, request, view):
        return True

    def has_object_permission(self, request, view, obj):
        return True

2、内置的权限类

2.1 AllowAny

允许任何用户访问,无论是否认证。


class AllowAny(BasePermission):
    def has_permission(self, request, view):
        return True

2.2 IsAuthenticated

只允许已认证的用户访问。


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

2.3 IsAdminUser

只允许管理员用户访问(user.is_staff = True)

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

2.4 IsAuthenticatedOrReadOnly

已认证用户或只读请求


SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')

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

2.5 DjangoModelPermissions

基于 Django 的模型权限系统,自动映射到 DRF 的 HTTP 方法,映射关系如下:

perms_map = {
        'GET': [],
        'OPTIONS': [],
        'HEAD': [],
        'POST': ['%(app_label)s.add_%(model_name)s'],
        'PUT': ['%(app_label)s.change_%(model_name)s'],
        'PATCH': ['%(app_label)s.change_%(model_name)s'],
        'DELETE': ['%(app_label)s.delete_%(model_name)s'],
    }


class DjangoModelPermissions(Baseermission):

    authenticated_users_only = True

    def has_permission(self, request, view):
        if not request.user or (
           not request.user.is_authenticated and self.authenticated_users_only):
            return False
        queryset = self._queryset(view)
        perms = self.get_required_permissions(request.method, queryset.model)

        return request.user.has_perms(perms)


2.6 DjangoModelPermissionsOrAnonReadOnly

类似于 DjangoModelPermissions,但允许匿名用户进行只读访问。

authenticated_users_only = False

2.7 DjangoObjectPermissions

基于 Django 的对象级权限,需要 django-guardian 包支持


class DjangoObjectPermissions(DjangoModelPermissions):
        def has_object_permission(self, request, view, obj):
        
        queryset = self._queryset(view)
        model_cls = queryset.model
        user = request.user

        perms = self.get_required_object_permissions(request.method, model_cls)

        if not user.has_perms(perms, obj):
            if request.method in SAFE_METHODS:
                raise Http404
            read_perms = self.get_required_object_permissions('GET', model_cls)
            if not user.has_perms(read_perms, obj):
                raise Http404
            return False
        return True

3、自定义权限类

创建自定义权限类需要继承 BasePermission 并实现 has_permission 和/或 has_object_permission 方法。


from rest_framework.permissions import BasePermission

class IsOwner(BasePermission):
    """
    自定义权限:只允许对象的所有者访问
    """
    
    def has_object_permission(self, request, view, obj):
        # 检查用户是否是对象的所有者
        return obj.owner == request.user


class IsOwnerOrReadOnly(BasePermission):
    """
    自定义权限:允许所有人读取,但只有所有者可以修改
    """
    
    def has_object_permission(self, request, view, obj):
        # 允许安全的HTTP方法(GET, HEAD, OPTIONS)
        if request.method in permissions.SAFE_METHODS:
            return True
        
        # 写操作只允许所有者
        return obj.owner == request.user

4、权限使用

4.1 全局权限配置


# settings.py
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
}

4.2 视图级权限配置


# 类视图
class MyView(APIView):
    permission_classes = [IsAuthenticated, IsOwner]

# 视图集
class MyViewSet(ModelViewSet):
    permission_classes = [IsAuthenticated, BusinessHoursOnly]

# 函数视图
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def my_view(request):
    return Response({"message": "Authenticated user only"})

5、DRF权限校验源码

APIView.dispatch->initial->check_permissions->


class APIView(View):
    def dispatch(self, request, *args, **kwargs):
        self.initial(request, *args, 


    def initial(self, request, *args, **kwargs):
        self.check_permissions(request)
    

    def check_permissions(self, request):
        # 循环调用每个权限类的has_permission方法,任何一个返回False则抛出异常
        for permission in self.get_permissions():
            if not permission.has_permission(request, self):
                self.permission_denied(
                    request,
                    message=getattr(permission, 'message', None),
                    code=getattr(permission, 'code', None)
                )

    
    # 该方法有被GenericAPIView中的get_object调用
    def check_object_permissions(self, request, obj):
        # 循环调用每个权限类的has_object_permission方法,任何一个返回False则抛出异常
        for permission in self.get_permissions():
            if not permission.has_object_permission(request, self, obj):
                self.permission_denied(
                    request,
                    message=getattr(permission, 'message', None),
                    code=getattr(permission, 'code', None)
                )
posted @ 2025-08-30 10:11  xclic  阅读(9)  评论(0)    收藏  举报