Django REST 权限类不能在 OR 中一起工作,而是按预期独立工作

Posted

技术标签:

【中文标题】Django REST 权限类不能在 OR 中一起工作,而是按预期独立工作【英文标题】:Django REST permission classes don't work together inside an OR but work as expected independently 【发布时间】:2021-08-13 05:15:45 【问题描述】:

我在使用 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 的两条注释行按预期工作,但是当我尝试将它们一起使用时,这意味着,作为一个完整用户或非安全方法的所有者,它总是允许一切。好像没有条件了。

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

【问题讨论】:

【参考方案1】:

经过一些研究,我发现在这个link 中报告了一个错误。作为一种解决方法,我将以下方法添加到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,)

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

【讨论】:

以上是关于Django REST 权限类不能在 OR 中一起工作,而是按预期独立工作的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Django Rest Framework 过滤器将过滤器链接在一起

Django REST框架--认证和权限

python Django Rest_Framework框架 认证权限限流功能组件详解(图文并茂版)

python Django Rest_Framework框架 认证权限限流功能组件详解(图文并茂版)

python Django Rest_Framework框架 认证权限限流功能组件详解(图文并茂版)

如何在 django rest 框架中添加自定义权限和角色