Django Rest Framework: 基于对象属性/所有权的权限设置

5 投票
1 回答
1640 浏览
提问于 2025-04-18 08:09

我想让用户能够创建和查看资源,但只有在以下情况下:

  1. 他们是工作人员,或者
  2. 他们是自己想要创建或查看的对象的“拥有者”

我已经搞定了只读权限,因为用户只有在使用他们的主键生成视图集时,才能获取对象列表。例如:GET /api/users/1/notes 只会返回主键为1的用户的笔记。

但是,在测试中,我发现用户可以通过将对象发布到自己的列表端点来创建一个“属于”其他用户的对象。例如,用户1可以向 /api/users/1/notes 发送一个POST请求,但指定的笔记数据是 {user: "http://host.tld/users/2/", text: "看!我在另一个人的账户里创建了一个笔记!"}

我下面有一个解决方案,似乎可以正常工作,不过我感觉自己在逆流而上。目前,在一个自定义权限中,我创建了一个将要创建的对象的实例,并检查它的拥有者是否是发起请求的用户。

有没有更简单的方法来做到这一点?

当前的解决方案:

def has_permission(self, request, view):
    if request.user.is_staff:
        return True
    elif request.method in permissions.SAFE_METHODS:
        # check that the user is looking for their own list
        return request.user == User.objects.get(pk=view.kwargs['user_pk'])
    elif request.method not in permissions.SAFE_METHODS:
        # the user can create/modify the object if the new object's user == the request user
        # roundabout way of figuring this out... probably a better way
        user_path = request.POST['user'].split(request.get_host())[1]
        func = resolve(user_path).func
        kwargs = resolve(user_path).kwargs
        user_for_object = func.cls.model.objects.get(pk=kwargs['pk'])
        return user_for_object == request.user
    else:
        return False

1 个回答

3

这要看你代码的其他部分。

通常情况下,DRF(Django REST Framework)会在一个叫做 check_object_permissions 的方法里进行对象级别的权限检查,这个方法是在你的 ViewSet 或权限后端中。

这个方法会被默认的 get_object 实现调用,用来检查权限,当任何通用视图尝试获取一个对象进行操作时。

如果你只使用通用的 ViewSets,并且 /notes 是一个 @action,那么这将是最简单的方法。

如果这些 ViewSets 中的 对象note,我建议你构建一些类似的东西(比如在一个 mixin 中添加到每个位于 /user/ 下的 ViewSet)。构建嵌套资源和它们的路由有很多不同的方法。

撰写回答