社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Django

Django rest framework视图集中的chainig权限

hamzeh_pm • 3 年前 • 1410 次点击  
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
 
1410 次点击  
文章 [ 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 将给出预期的行为。