【问题标题】:How to invoke DRF has_object_permission() method with a function based view and Token auth?如何使用基于函数的视图和令牌身份验证调用 DRF has_object_permission() 方法?
【发布时间】:2021-04-06 19:44:11
【问题描述】:

我正在使用带有身份验证的 DRF。我已经实现了会话和令牌认证。第一个由我用来调试的可浏览 API 使用,第二个是实际客户端将使用的身份验证。我有以下详细视图:

@api_view(['GET', 'PUT', 'DELETE'])
@permission_classes([permissions.IsAuthenticated, IsTrainingOwner])  # this view is only available to authenticated users
def training_detail(request, pk, format=None):
    """
    Retrieve, update or delete a training. Need to be authenticated
    """
    print(request.user)
    try:
        training = Training.objects.get(pk=pk)
    except Training.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':
        serializer = TrainingSerializer(training)
        return Response(serializer.data)

    elif request.method == 'PUT':
        serializer = TrainingSerializer(training, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    elif request.method == 'DELETE':
        training.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

如您所见,我正在使用自定义权限:

class IsTrainingOwner(permissions.BasePermission):
    """
    Custom permission to only allow owners of an object to see and edit it
    """

    def has_object_permission(self, request, view, obj):
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            print("Object owner: ", obj.owner)
            print("Request user: ", request.user)
            return True

        # Instance must have an attribute named `owner`.
        print("Object owner: ", obj.owner)
        print("Request user: ", request.user)
        return obj.owner == request.user

当我使用 DRF 可浏览 API 时,此自定义权限被正确调用,对象所有者和请求用户的打印显示在我的控制台中。

但是,当我使用 Postman 测试 Token 权限时,根本没有调用“has_object_permission”方法(我在控制台中没有看到任何打印),我可以在发送时修改用户 A 的培训标头中用户 B 的令牌。

我已经阅读了有关此问题的 DRF 文档,然后决定尝试通用视图:

class TrainingDetail(generics.RetrieveUpdateAPIView):
    permission_classes = [permissions.IsAuthenticated, IsTrainingOwner]
    queryset = Training.objects.all()
    serializer_class = TrainingSerializer

使用通用视图效果很好,并且可以正确调用自定义权限。

所以,我的问题是: 当我使用使用会话身份验证的可浏览 API 并且我需要切换到通用视图版本才能使自定义权限与 POSTMAN 一起使用时,为什么自定义权限可以与基于函数的视图版本一起使用?

感谢您的帮助:)

【问题讨论】:

    标签: django authentication django-rest-framework


    【解决方案1】:

    查看 DRF 文档: https://www.django-rest-framework.org/api-guide/permissions/#object-level-permissions

    如果您正在编写自己的视图并希望强制执行对象级别权限,或者如果您在通用视图上覆盖 get_object 方法,那么您需要显式调用 .check_object_permissions(request, obj) 方法查看您检索对象的点。

    我认为,在通过 HTML 接口与 API 交互的情况下,DRF 会在渲染 HTML 表单时调用check_object_permissions,而您的视图根本不会触及它。

    请尝试通过浏览器开发工具提取会话 cookie,并尝试使用 POSTMAN/curl 发送相同的请求以触发 JSONRenderer 而不是 BrowsableAPIRenderer(您也可以通过在 url 中添加 ?format=json 来强制执行此操作)。

    【讨论】:

    • 感谢您的回答@Snake9920。我认为你是对的。问题是我试图在基于函数的视图中调用 check_object_permissions 方法,但我不得不承认我并不确切知道如何执行此操作。鉴于我分享的代码,您能否给我一个提示如何做到这一点?谢谢!
    • @DrSalas 您只需在检索训练对象后立即调用self.check_object_permissions(self.request, training)
    猜你喜欢
    • 2015-10-14
    • 2017-06-05
    • 2021-02-08
    • 2023-03-29
    • 2015-10-07
    • 2017-12-28
    • 2018-02-09
    • 2021-01-25
    • 2020-06-23
    相关资源
    最近更新 更多