I'd like to allow users to create and view resources, but only if:
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.
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!"}
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.
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.
If you use only Generic ViewSets and /notes
is an @action
this would be the easiest way.
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/
).
There are many different approaches to build nested resources and the routing for them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With