首页 > 解决方案 > Django REST 权限类不能在 OR 中一起工作,而是按预期独立工作

问题描述

我在使用 OR 运算符将两个权限放在一起时遇到了麻烦。文档说: Doc

如果它们从 rest_framework.permissions.BasePermission 继承,则可以使用标准 Python 位运算符组成权限。例如,IsAuthenticatedOrReadOnly 可以写成: ... permission_classes = [IsAuthenticated|ReadOnly]

所以我创建了权限: permissions.py

class IsFullUserOrReadOnly(permissions.BasePermission):
    """
    This class defines the permission to only allow the request to certain users with a
    certain role."""
    def has_permission(self, request, view):
        """
        This function overrides the default has_permission method to allow the writing methods
        only to full users or admin users
        """

        if request.method in permissions.SAFE_METHODS:
            return True

        is_full_user = False


        queryset = User.objects.get(email=request.user)
        if queryset:
            user = UserSerializer(queryset)
            if 'roles' in user.data:
                for role in user.data['roles']:
                    if role == ADMIN or role == FULL_USER:
                        is_full_user = True

        print('IsFullUserOrReadOnly')
        print(is_full_user)
        print(request.method)
        print(request.method =='POST')
        return is_full_user or request.method =='POST'

class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    This class defines the permission to only allow the POST and PUT methods to the creator of
    the item."""
    def has_object_permission(self, request, view, obj):
        """
        This function overrides the default has_object_permission method to allow the writing
        methods to the owner of the object
        """
        if request.method in permissions.SAFE_METHODS:
            return True

        # Instance must have an attribute named `created_by`.
        print('IsOwnerOrReadOnly')
        print(obj.created_by == request.user)

        return obj.created_by == request.user

然后我将它们添加到我的视图中: view.py


class ItemViewset(viewsets.ModelViewSet): # pylint: disable=too-many-ancestors
    """API Endpoint to return the list of items"""
    queryset = Item.objects.all()
    serializer_class = ItemSerializer
    # permission_classes = (IsAuthenticated, IsFullUserOrReadOnly,)
    permission_classes = [IsAuthenticated, IsFullUserOrReadOnly|IsOwnerOrReadOnly,]
    # permission_classes = [IsAuthenticated, IsOwnerOrReadOnly]

两条注释行按预期工作,permission_classes 但是当我尝试将它们一起使用时,这意味着,作为一个完整用户或非安全方法的所有者,它总是允许一切。看起来那里没有条件了。

我不知道我是否遗漏了什么,但据我所知,这应该可行。我错过了什么吗?

标签: pythondjangopermissionsdjango-rest-authdjango-rest-viewsets

解决方案


经过一些研究,我在此链接中发现了一个错误报告。作为一种解决方法,我将以下方法添加到IsFullUserOrReadOnly

    def has_object_permission(self, request, view, obj):
        """ 
        This function overrides the default has_object_permission to prevent the bug documented in:
        https://github.com/encode/django-rest-framework/issues/7117
        """

        return self.has_permission(request, view)

然后我将顺序切换为:

    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly|IsFullUserOrReadOnly,)

而且似乎确实可以解决问题


推荐阅读