Py学习  »  Django

Django rest framework视图集中的chainig权限

hamzeh_pm • 3 年前 • 1401 次点击  
class UserViewSet(viewsets.ModelViewSet):
    def list(self, request):
        users = User.objects.all()
        serializer = UserSerializer(users, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def create(self, request):
        serializer = UserSerializer(data=request.data)

        if serializer.is_valid(raise_exception=True):
            pass

    def retrieve(self, request, pk):
        user = get_object_or_404(User, pk=pk)
        self.check_object_permissions(request, user)
        serializer = UserSerializer(user)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def get_permissions(self):
        if self.action == "list":
            permission_classes = [
                IsAdminUser,
            ]
        elif self.action == "create":
            permission_classes = [AllowAny]
        else:
            permission_classes = [AccountOwnerPermission | IsAdminUser ]

        return [permission() for permission in permission_classes]

自定义权限为:

class AccountOwnerPermission(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        print(object)
        print(request.user)
        return obj == request.user

首先,我没有获得对象权限,但在@brian destura的帮助下,我解决了这个问题 the previous question 现在的问题是,当我将2个权限链接在一起时,它的行为就像 允许的 我一个接一个地检查它们,两个权限都正常工作,其中一个 允许管理员 其中一个 允许所有者 但当他们在一起或在一起时,一切都会一团糟

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/129172
 
1401 次点击  
文章 [ 2 ]  |  最新文章 3 年前
rzlvmp
Reply   •   1 楼
rzlvmp    3 年前

@凯尔已经描述了这个问题,他的答案应该被接受

但我会尝试添加一些细节:

  1. 当我们链接两个权限类时,DRF会创建一个新的权限类 OR 课程:
>>> from rest_framework.permissions import IsAdminUser 
>>> or_class = [IsAdminUser | IsAdminUser]
>>> len(or_class)
1
>>> print(or_class)
[<rest_framework.permissions.OperandHolder object at 0x1096d5fa0>]
>>> 
  1. 德扬戈 documentation 他说 has_object_permission (检查确切对象的权限)方法在之后运行 has_permission (检查整个视图类的权限)

  2. 让我们看看这些方法在内部是如何链接的 课程:

>>> import inspect
>>> or_instance = or_class[0]()
>>> print(inspect.getsource(or_instance.has_permission))
    def has_permission(self, request, view):
        return (
            self.op1.has_permission(request, view) or
            self.op2.has_permission(request, view)
        )

>>> print(inspect.getsource(or_instance.has_object_permission))
    def has_object_permission(self, request, view, obj):
        return (
            self.op1.has_object_permission(request, view, obj) or
            self.op2.has_object_permission(request, view, obj)
        )

所以我们可以看到DRF检查了这两个 你有许可吗 然后我们两个 拥有_object _权限

你有许可吗 检查可能会被跳过,因为我们正在运行 拥有_object _权限 之后

但是 拥有_object _权限 没有在内部实现 IsAdminUser 权限类,但它是在父类中实现的 BasePermission 类,看起来像:

class BasePermission(metaclass=BasePermissionMetaclass):
    def has_object_permission(self, request, view, obj):
        return True

所以 艾德明 总是回来 True 在…上 拥有_object _权限 .通常情况下 艾德明 应该失败 你有许可吗 ,但在你的 你有许可吗 已通过,因为它未在内部实现 AccountOwnerPermission

最简单的解决方案是添加 你有许可吗 方法 帐户所有者权限 课程:

class AccountOwnerPermission(permissions.BasePermission):
    def has_permission(self, request, view, obj):
        return False
Kyell
Reply   •   2 楼
Kyell    3 年前

当链接权限时,例如

permission_classes = [AccountOwnerPermission, IsAdminUser]

它的行为类似于权限类之间的AND运算符

最好的选择是创建一个新的权限,该权限允许权限逻辑。

class AdminOrAccountOwnerPermission(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        return obj == request.user or request.user.id_admin

或者,当使用的权限具有长而复杂的代码以保持代码干燥时:

class AdminOrAccountOwnerPermission(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        return AccountOwnerPermission().has_object_permission(request, view, obj) or IsAdminUser().has_object_permission(request, view, obj)

编辑: 请回答评论中的问题,说明其行为的原因 AllowAny . AccountOwnerPermission has_object_permission 但是没有 has_permission 另一方面 IsAdminUser 你有许可吗 但是没有 拥有_object _权限 实施。

当这些函数未实现时,函数返回 True 默认情况下(从 BasePermission ).因此,在跑步时 你有许可吗 , 帐户所有者权限 总是回来 符合事实的 跑步时 拥有_object _权限 , 艾德明 他总是回来 符合事实的 .

实施 AccountOwnerPermission.has_permission 将给出预期的行为。