DRF 视图集中的权限检查无法正常工作
Permission checks in DRF viewsets are not working right
我正在实施一个 API 嵌套结构。
假设这是一个动物园,我可以调用 GET /api/cage/
获取笼子列表 GET /api/cage/1/
获取笼子 ID 1,然后我可以 GET /api/cage/1/animals/
获取列表那个笼子里的动物。
我遇到的问题是权限问题。如果我能看到笼子本身,我应该只能看到笼子里的动物。如果has_object_permission()
returns True
在相关权限 class.
中,我应该能够看到笼子本身
出于某种原因,has_object_permission()
在我执行 GET /api/cage/1/
时被调用,但 has_permission()
在我调用 GET /api/cage/1/animals/
时被调用。使用 has_permission()
我无权访问该对象来检查权限。我错过了什么吗?我该怎么做?
我的 cage viewset 大致像这样
class CageViewSet(ModelViewSet):
queryset = Cage.objects.all()
serializer_class = CageSerializer
permission_classes = [GeneralZooPermissions, ]
authentication_classes = [ZooTicketCheck, ]
def get_queryset(self):
... code to only list cages you have permission to see ...
@detail_route(methods=['GET'])
def animals(self, request, pk=None):
return Request(AnimalSerializer(Animal.objects.filter(cage_id=pk), many=True).data)
我的 GeneralZooPermissions
class 看起来像这样(目前)
class GeneralZooPermissions(BasePermission):
def has_permission(self, request, view):
return True
def has_object_permission(self, request, view, obj):
return request.user.has_perm('view_cage', obj)
这似乎是 DRF 中的一个错误。详细的路由没有调用正确的权限检查。我曾尝试向 DRF 开发人员报告此问题,但我的报告似乎已消失。不知道下一步该怎么做。想法?
我用 DRF 发布的问题又回来了,我得到了回复。似乎只检查 has_permission()
而不是 has_object_permission()
是预期的行为。这对我没有帮助。在这一点上,必须做这样的事情:
class CustomPermission(BasePermission):
def has_permission(self, request, view):
"""we need to do all permission checking here, since has_object_permission() is not guaranteed to be called"""
if 'pk' in view.kwargs and view.kwargs['pk']:
obj = view.get_queryset()[0]
# check object permissions here
else:
# check model permissions here
def has_object_permission(self, request, view, obj):
""" nothing to do here, we already checked everything """
return True
好的,所以在阅读了一堆 DRF 的代码并在 DRF GitHub 页面上发布了一个问题之后。
似乎只有当您的视图调用 get_object()
来检索要操作的对象时才会调用 has_object_permission()
。
这是有道理的,因为您无论如何都需要检索对象来检查权限,如果他们透明地这样做,则会添加额外的数据库查询。
回复我报告的人说他们需要更新文档以反映这一点。所以,这个想法是,如果你想写一个自定义的详细路由并让它正确检查权限,你需要做
class MyViewSet(ModelViewSet):
queryset = MyModel.objects.all()
....
permission_classes = (MyCustomPermissions, )
@detail_route(methods=['GET', ])
def custom(self, request, pk=None):
my_obj = self.get_object() # do this and your permissions shall be checked
return Response('whatever')
如果您想在执行另一个不调用 get_object()
的方法(例如 POST
方法)时定义权限,您可以覆盖 has_permission 方法。也许这个答案可以帮助 ()
您可以做的另一件事是在 POST
方法中使用 check_object_permissions
,这样您就可以调用 has_object_permission
方法:
@action(detail=True, methods=["POST"])
def cool_post(self, request, pk=None, *args, **kwargs):
your_obj = self.get_object()
self.check_object_permissions(request, your_obj)
我正在实施一个 API 嵌套结构。
假设这是一个动物园,我可以调用 GET /api/cage/
获取笼子列表 GET /api/cage/1/
获取笼子 ID 1,然后我可以 GET /api/cage/1/animals/
获取列表那个笼子里的动物。
我遇到的问题是权限问题。如果我能看到笼子本身,我应该只能看到笼子里的动物。如果has_object_permission()
returns True
在相关权限 class.
出于某种原因,has_object_permission()
在我执行 GET /api/cage/1/
时被调用,但 has_permission()
在我调用 GET /api/cage/1/animals/
时被调用。使用 has_permission()
我无权访问该对象来检查权限。我错过了什么吗?我该怎么做?
我的 cage viewset 大致像这样
class CageViewSet(ModelViewSet):
queryset = Cage.objects.all()
serializer_class = CageSerializer
permission_classes = [GeneralZooPermissions, ]
authentication_classes = [ZooTicketCheck, ]
def get_queryset(self):
... code to only list cages you have permission to see ...
@detail_route(methods=['GET'])
def animals(self, request, pk=None):
return Request(AnimalSerializer(Animal.objects.filter(cage_id=pk), many=True).data)
我的 GeneralZooPermissions
class 看起来像这样(目前)
class GeneralZooPermissions(BasePermission):
def has_permission(self, request, view):
return True
def has_object_permission(self, request, view, obj):
return request.user.has_perm('view_cage', obj)
这似乎是 DRF 中的一个错误。详细的路由没有调用正确的权限检查。我曾尝试向 DRF 开发人员报告此问题,但我的报告似乎已消失。不知道下一步该怎么做。想法?
我用 DRF 发布的问题又回来了,我得到了回复。似乎只检查 has_permission()
而不是 has_object_permission()
是预期的行为。这对我没有帮助。在这一点上,必须做这样的事情:
class CustomPermission(BasePermission):
def has_permission(self, request, view):
"""we need to do all permission checking here, since has_object_permission() is not guaranteed to be called"""
if 'pk' in view.kwargs and view.kwargs['pk']:
obj = view.get_queryset()[0]
# check object permissions here
else:
# check model permissions here
def has_object_permission(self, request, view, obj):
""" nothing to do here, we already checked everything """
return True
好的,所以在阅读了一堆 DRF 的代码并在 DRF GitHub 页面上发布了一个问题之后。
似乎只有当您的视图调用 get_object()
来检索要操作的对象时才会调用 has_object_permission()
。
这是有道理的,因为您无论如何都需要检索对象来检查权限,如果他们透明地这样做,则会添加额外的数据库查询。
回复我报告的人说他们需要更新文档以反映这一点。所以,这个想法是,如果你想写一个自定义的详细路由并让它正确检查权限,你需要做
class MyViewSet(ModelViewSet):
queryset = MyModel.objects.all()
....
permission_classes = (MyCustomPermissions, )
@detail_route(methods=['GET', ])
def custom(self, request, pk=None):
my_obj = self.get_object() # do this and your permissions shall be checked
return Response('whatever')
如果您想在执行另一个不调用 get_object()
的方法(例如 POST
方法)时定义权限,您可以覆盖 has_permission 方法。也许这个答案可以帮助 ()
您可以做的另一件事是在 POST
方法中使用 check_object_permissions
,这样您就可以调用 has_object_permission
方法:
@action(detail=True, methods=["POST"])
def cool_post(self, request, pk=None, *args, **kwargs):
your_obj = self.get_object()
self.check_object_permissions(request, your_obj)