Django - How can I prevent access to other users' objects?

Viewed 1055

Let's assume that I have such URL users/{id}/objects and I am authenticated as a User with ID equals 1. At the moment I can access objects of users with ID equals 2, 3 etc. Does anyone have an idea how can I prevent this?

class UserObject(GenericAPIView):

    permission_classes = [UserPermission]
    def get(self, request, user_id):

            try:
                object = Object.objects.filter(user=user_id)
            except Object.DoesNotExist:
                return Response(status=status.HTTP_404_NOT_FOUND)
            serializer = ObjectSerializer(object, many=True)
            return Response(serializer.data)


class UserPermission(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user and request.user.is_authenticated():
            return True
        return False

I tried in this way:

serializer_class = ObjectSerializer
permission_classes = [IsAuthenticated, ]

def get_queryset(self):
    return Object.objects.filter(owner=self.request.user)

def get(self, request, user_id):

        try:
            object = Object.objects.filter(user=user_id)
        except Object.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        serializer = ObjectSerializer(object, many=True)
        return Response(serializer.data)
2 Answers

If you overload the view's get_queryset to only return objects belonging to the current user then Django will handle the appropriate errors and responses on its own. For example,

class MyView(GenericAPIView):

    serializer_class = serializers.MySerializer
    permission_classes = (IsAuthenticated,)

    def get_queryset(self):
        return MyModel.objects.filter(owner=self.request.user)

See also http://www.django-rest-framework.org/api-guide/generic-views/#attributes

You can use the IsAuthenticated permission only to check if someone is logged in and than check "manually" if the user is asking for data of its own or not. Like this:

class UserObject(GenericAPIView):

    permission_classes = (IsAuthenticated,)
    def get(self, request, user_id):

        if (str(reques.user.id) != user_id):
            return Response(status=status.HTTP_403_FORBIDDEN)

        try:
            object = Object.objects.filter(user=user_id)
        except Object.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)

        serializer = ObjectSerializer(object, many=True)
        return Response(serializer.data)

If you really want to use a custom permission your can leave you view untouched and make you permission classe like this:

class UserPermission(permissions.BasePermission):

    def has_permission(self, request, view):
        if (not request.user.is_authenticated()):
            return False

        user_id = request.path.split('/')[1]

        if (str(request.user.id) == user_id):
            return True

        return False

Note: I'd recomend the first option.

Note: this code is an example, if it doen't work right away, try to understand the idea and adapt it. I didn't tested it and it may need some ajusts, specially the part that gets the user_id frorm response.path.

Related