Django rest framework ViewSet 中的 chainig 权限
chainig permission in Django rest framework ViewSet
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 的帮助下我解决了这个问题
现在的问题是,当我将 2 个权限链接在一起时,它的行为就像 AllowAny 我一个一个地检查它们,两个权限都工作正常,其中一个 allow admin 其中之一 允许拥有者 但是当他们在一起时,一切都会变得混乱
像
这样链接权限时
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
有 has_permission
但没有 has_object_permission
实现。
当这些函数没有实现时,函数默认为return True
(来自BasePermission
)。结果,当运行 has_permission
, AccountOwnerPermission
总是returns True
当运行 has_object_permission
, IsAdminUser
总是 returning True
.
实施 AccountOwnerPermission.has_permission
会产生预期的行为。
@Kyell 已经描述了问题,他的回答应该被采纳
但我会尝试添加一些细节:
- 当我们链接两个权限时 classes DRF 会创建一个新的
OR
class:
>>> from rest_framework.permissions import IsAdminUser
>>> or_class = [IsAdminUser | IsAdminUser]
>>> len(or_class)
1
>>> print(or_class)
[<rest_framework.permissions.OperandHolder object at 0x1096d5fa0>]
>>>
Django documentation 表示 has_object_permission
(检查确切对象的权限)方法 运行ning 在 has_permission
之后(检查整个视图的权限 class)
让我们看看这些方法在链式中看起来如何 OR
class:
>>> 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 检查了 has_permission
之后又检查了 has_object_permission
has_permission
检查可能会被跳过,因为我们 运行 has_object_permission
之后。
但是! has_object_permission
未在 IsAdminUser
权限 class 内实现,但在父级 BasePermission
class 内实现,看起来像:
class BasePermission(metaclass=BasePermissionMetaclass):
def has_object_permission(self, request, view, obj):
return True
所以 IsAdminUser
总是 return True
has_object_permission
。在通常情况下 IsAdminUser
应该在 has_permission
上失败,但是在你的 OR
class has_permission
中通过了,因为它没有在 AccountOwnerPermission
[=64 中实现=]
最简单的解决方案是将 has_permission
方法添加到 AccountOwnerPermission
class:
class AccountOwnerPermission(permissions.BasePermission):
def has_permission(self, request, view, obj):
return False
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 的帮助下我解决了这个问题
像
这样链接权限时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
有 has_permission
但没有 has_object_permission
实现。
当这些函数没有实现时,函数默认为return True
(来自BasePermission
)。结果,当运行 has_permission
, AccountOwnerPermission
总是returns True
当运行 has_object_permission
, IsAdminUser
总是 returning True
.
实施 AccountOwnerPermission.has_permission
会产生预期的行为。
@Kyell 已经描述了问题,他的回答应该被采纳
但我会尝试添加一些细节:
- 当我们链接两个权限时 classes DRF 会创建一个新的
OR
class:
>>> from rest_framework.permissions import IsAdminUser
>>> or_class = [IsAdminUser | IsAdminUser]
>>> len(or_class)
1
>>> print(or_class)
[<rest_framework.permissions.OperandHolder object at 0x1096d5fa0>]
>>>
Django documentation 表示
has_object_permission
(检查确切对象的权限)方法 运行ning 在has_permission
之后(检查整个视图的权限 class)让我们看看这些方法在链式中看起来如何
OR
class:
>>> 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 检查了 has_permission
之后又检查了 has_object_permission
has_permission
检查可能会被跳过,因为我们 运行 has_object_permission
之后。
但是! has_object_permission
未在 IsAdminUser
权限 class 内实现,但在父级 BasePermission
class 内实现,看起来像:
class BasePermission(metaclass=BasePermissionMetaclass):
def has_object_permission(self, request, view, obj):
return True
所以 IsAdminUser
总是 return True
has_object_permission
。在通常情况下 IsAdminUser
应该在 has_permission
上失败,但是在你的 OR
class has_permission
中通过了,因为它没有在 AccountOwnerPermission
[=64 中实现=]
最简单的解决方案是将 has_permission
方法添加到 AccountOwnerPermission
class:
class AccountOwnerPermission(permissions.BasePermission):
def has_permission(self, request, view, obj):
return False