首页 文章

DRF视图集中的权限检查无法正常工作

提问于
浏览
3

我正在实现一个API,我有嵌套结构 . 让我们说它是一个动物园,我可以拨打 GET /api/cage/ 获取一个笼子 GET /api/cage/1/ 列表来获得笼子ID 1,但是我可以 GET /api/cage/1/animals/ 来获得该笼子中的动物列表 . 我遇到的问题是权限 . 如果我能看到笼子本身,我应该只能看到笼子里的动物 . 如果has_object_permission()在相关的权限类中返回True,我应该能够看到笼子本身 . 出于某种原因,当我执行GET / api / cage / 1 /时会调用has_object_permission(),但是当我调用 GET /api/cage/1/animals/ 时会调用has_permission() . 使用has_permission(),我无权访问该对象来检查权限 . 我错过了什么吗?我该怎么做呢?

我的笼子视图看起来或多或少像这样

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 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)

更新#1:看起来这是DRF中的一个错误 . 详细信息路由不会调用正确的权限检查 . 我曾尝试向DRF开发者报告此问题,但我的报告似乎已经消失 . 不知道下一步该怎么做 . 想法?

更新#2:我在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

1 回答

  • 8

    好的,所以在阅读了一堆DRF代码并向DRF团队发布问题之后,如果您的视图调用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')
    

相关问题