简体   繁体   English

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

[英]Django Rest Framework: Permissions based on Object Attributes/Ownership

I'd like to allow users to create and view resources, but only if: 我想允许用户创建和查看资源,但仅限于:

  1. They are staff OR 他们是工作人员或
  2. They are the 'owner' of the object they're trying to create/view 他们是他们试图创建/查看的对象的“所有者”

I've got read-only permissions worked out fine, since users only have permission to get lists of objects when their primary key is used to generate the viewset. 我已经获得了只读权限,因为用户只有在使用主键生成视图集时才能获取对象列表。 For example: GET /api/users/1/notes returns just the notes for the user with pk=1. 例如:GET / api / users / 1 / notes仅返回pk = 1的用户注释。

However, in testing, I discovered that users can create an object 'owned' by another user by posting it to their own list endpoint. 但是,在测试中,我发现用户可以通过将其发布到自己的列表端点来创建另一个用户“拥有”的对象。 For example user 1 can send a POST to /api/users/1/notes, but specify the note data as {user: " http://host.tld/users/2/ ", text: "Look! I created a note in another person's account!"} 例如,用户1可以向/ api / users / 1 / notes发送POST,但是将注释数据指定为{user:“ http://host.tld/users/2/ ”,文本:“看!我创建了一个请注意另一个人的帐户!“}

I've got a fix below that seems to work fine, though I get the feeling I'm swimming against the current. 我有一个下面似乎工作得很好的修复,虽然我感觉我正在逆流而行。 Right now, within a custom permission, I create an instance of the object that would be created and check that its owner is the user making the request. 现在,在自定义权限内,我创建了一个将要创建的对象的实例,并检查其所有者是否是发出请求的用户。

Is there a cleaner way of doing this? 这样做有更干净的方法吗?

Current Fix: 当前修复:

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

It depends on the rest of your code. 这取决于你的其余代码。

Normally DRF does object-level checks in a method called check_object_permissions in your ViewSet or permission backend. 通常DRF确实对象级检查,在一个名为方法check_object_permissionsViewSet或允许后端。

This method gets called by (the default implementation) of get_object to check the permissions when any of the generics tries to get an object to work on. 此方法由get_object的(默认实现) get_object以在任何泛型尝试使对象工作时检查权限。

If you use only Generic ViewSets and /notes is an @action this would be the easiest way. 如果你只使用Generic ViewSets和/notes@action这将是最简单的方法。

If the object in these ViewSets is the note , I would suggest to build something looking similar (for example in a mixin you add to every ViewSet sitting under /user/ ). 如果这些ViewSets中的对象note ,我建议构建类似的东西(例如,在添加到/user/下的每个ViewSet的mixin中)。 There are many different approaches to build nested resources and the routing for them. 有许多不同的方法来构建嵌套资源及其路由。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM