[英]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]
and custom permission is:和自定义权限是:
class AccountOwnerPermission(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
print(object)
print(request.user)
return obj == request.user
first i dont get object permission but with help of @brian-destura at this question i fixed that part the previous question now the problem is when i chain 2 permission together it behave like AllowAny i check them one by one and both permissions work fine, one of them allow admin and one of them allow owner but when they are or together it mess everything up首先,我没有获得 object 许可,但是在@brian-destura 在这个问题上的帮助下,我修复了上一个问题的那部分,现在问题是当我将 2 个权限链接在一起时,它的行为就像AllowAny我一个一个检查它们,两个权限都可以正常工作,其中一个允许管理员,其中一个允许所有者,但是当他们在一起或在一起时,一切都搞砸了
When chaining permissions like当链接权限时
permission_classes = [AccountOwnerPermission, IsAdminUser]
it behaves like an AND operator between the permission classes它的行为类似于权限类之间的 AND 运算符
The best option is to create a new permission that allows either the permission logic.最好的选择是创建一个允许任一权限逻辑的新权限。
class AdminOrAccountOwnerPermission(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj == request.user or request.user.id_admin
or this when the permissions used have long complex code to keep code DRY:或者当使用的权限有很长的复杂代码以保持代码干燥时:
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)
@Kyell already described the problem and his answer should be accepted @Kyell 已经描述了这个问题,他的回答应该被接受
But I'll try to add some details:但我会尝试添加一些细节:
OR
class: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 says that has_object_permission
(check permissions for exact object) method running after has_permission
(check permissions for whole view class) Django 文档说
has_object_permission
(检查确切对象的权限)方法在has_permission
之后运行(检查整个视图类的权限)
Let's see how looks these methods inside chained OR
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)
)
So we can see that DRF check both of has_permission
and after that both of has_object_permission
所以我们可以看到 DRF 检查了
has_permission
和之后的has_object_permission
has_permission
check may be skipped because we run has_object_permission
after. has_permission
检查可能会被跳过,因为我们在之后运行has_object_permission
。
But!但!
has_object_permission
is not implemented inside IsAdminUser
permission class but it is implemented inside parent BasePermission
class and looks like: has_object_permission
未在IsAdminUser
权限 class 内部实现,但它在父BasePermission
class 内部实现,如下所示:
class BasePermission(metaclass=BasePermissionMetaclass):
def has_object_permission(self, request, view, obj):
return True
So IsAdminUser
always return True
on has_object_permission
.所以
IsAdminUser
总是在has_object_permission
上返回True
。 In usual cases IsAdminUser
should fail on has_permission
, but in your OR
class has_permission
passed because it is not implemented inside AccountOwnerPermission
class在通常情况下
IsAdminUser
应该在has_permission
上失败,但在您的OR
class has_permission
通过,因为它没有在AccountOwnerPermission
中实现
Simplest solution will be to add has_permission
method to AccountOwnerPermission
class:最简单的解决方案是将
has_permission
方法添加到AccountOwnerPermission
class:
class AccountOwnerPermission(permissions.BasePermission):
def has_permission(self, request, view, obj):
return False
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.