[英]Django REST Framework - Allow staff to access all endpoints
I'm building a DRF API, and I would like to allow staff members ( is_staff == True
) to access all of the REST endpoints, while still providing custom permission checking per ViewSet.我正在构建一个 DRF API,我希望允许工作人员 (
is_staff == True
) 访问所有 REST 端点,同时仍然为每个 ViewSet 提供自定义权限检查。 Ideally, this would be a global setting, but I'm not against setting it up per ViewSet.理想情况下,这将是一个全局设置,但我不反对按 ViewSet 进行设置。
Here are the things I've tried:以下是我尝试过的事情:
from rest_framework import permissions
class SomeModelPermission(permissions.BasePermission):
def has_permission(self, request, view):
if request.user.is_staff:
return True
# other logic
def has_object_permission(self, request, view, obj):
if request.user.is_staff:
return True
# other logic
This works, but I'd rather not repeat so much code.这有效,但我不想重复这么多代码。
I tried removing the is_staff
logic from the custom permission above, and adding this to the ViewSet:我尝试从上面的自定义权限中删除
is_staff
逻辑,并将其添加到 ViewSet:
from rest_framework import permissions, viewsets
class SomeModelViewSet(viewsets.ModelViewSet):
permission_classes = (permissions.IsAdminUser|SomeModelPermission,)
However, this actually does not enforce permissions as I'd like, because IsAdminUser
inherits from BasePermission
, which is defined as:但是,这实际上并没有像我希望的那样强制执行权限,因为
IsAdminUser
继承自BasePermission
,其定义为:
class BasePermission(object):
def has_permission(self, request, view):
return True
def has_object_permission(self, request, view, obj):
return True
IsAdminUser
doesn't define its own has_object_permission
, so it will always return True
when checking object permissions, resulting in unintended object access. IsAdminUser
并没有定义自己的has_object_permission
,所以在检查对象权限时总是返回True
,导致意外的对象访问。
Any ideas?有任何想法吗? I was hoping there would be some way I could set a global permissions check that would return
True
when the user is a staff member, and defer to the custom permissions otherwise.我希望有某种方法可以设置全局权限检查,当用户是工作人员时返回
True
,否则遵循自定义权限。 But reading through how permissions are determined , I'm not sure that this is possible.但是阅读权限是如何确定的,我不确定这是可能的。
How about creating your own IsAdminUser
which also defines has_object_permission
?如何创建自己的
IsAdminUser
也定义了has_object_permission
? You could just inherit from the existing one:您可以从现有的继承:
from rest_framework.permissions import IsAdminUser as BaseIsAdminUser
class IsAdminUser(BaseIsAdminUser):
def has_object_permission(self, request, view, obj):
# Just reuse the same logic as `has_permission`...
return self.has_permission(request, view)
Then you can do what you attempted above, with the bitwise operator:然后,您可以使用按位运算符执行上面尝试的操作:
from rest_framework import permissions, viewsets
from your_own_project.permissions import IsAdminUser
class SomeModelViewSet(viewsets.ModelViewSet):
permission_classes = (IsAdminUser|SomeModelPermission,)
A bit "hacky" in some ways, but you could try to create your own permission types on the fly.在某些方面有点“hacky”,但您可以尝试动态创建自己的权限类型。
So the end result would look something like:所以最终的结果应该是这样的:
class SomeModelViewSet(viewsets.ModelViewSet):
permission_classes = skip_for_staff((SomeModelPermission, SomeOtherPermission, ...))
With the implementation something similar to:随着实现类似于:
class StaffAllowedMixin:
def has_permission(self, request, view):
if request.user.is_staff:
return True
return super().has_permission(request, view)
def has_object_permission(self, request, view, obj):
if request.user.is_staff:
return True
return super().has_object_permission(request, view, obj)
def skip_for_staff(permission_classes):
# You can probably also use a comprehension here, but for clarity:
staff_allowed_classes = []
for permission_class in permissions(
staff_allowed_classes.append(
# Create a new type (class) with name StaffAllowed<...>
type(f"StaffAllowed{permission_class}",
# Inherit from the mixin above, and from the original class
(StaffAllowedMixin, permission_class),
# empty dictionary means you don't want to override any attributes
{})
)
return tuple(staff_allowed_classes)
Essentially, for each permission class, you create a new class with the extra mixin that takes precedence and checks if the user is staff.本质上,对于每个权限类,您使用额外的 mixin 创建一个新类,该类优先并检查用户是否是员工。 But you do that on the fly, where your permissions are used, instead of having to predefine it for every permission.
但是您可以在使用您的权限的情况下即时执行此操作,而不必为每个权限预定义它。
There is a permission class for admin users.管理员用户有一个权限类。 Here is an example of that:
这是一个例子:
class deletecompletedreopenjobAPIView(RetrieveUpdateAPIView):
queryset = Job.objects._all()
serializer_class = JobCompletedDeleteStatusSerializer
lookup_field = 'job_id'
permission_classes = [IsOwnerOrReadOnly | **IsAdminUser**]
authentication_classes = (authentication.TokenAuthentication,)
My custom IsOwnerOrReadOnly is as follows:我的自定义 IsOwnerOrReadOnly 如下:
class IsOwnerOrReadOnly(BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
return obj.user == request.user
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.