Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django rest framework ignores has_object_permission

I'm trying to limit the access to objects for users. Only creaters should modify objects. For that purpose like they say in tutorial I've written

class IsOwnerOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        return False

and added it to permission_classes. But still any user can modify any object. If I add method

    def has_permission(self, request, view):
        return False

nobody can do anything. So all behaviour is controlled by the only has_permission method that doesn't provide any way to handle per object permissions. So am I doing something wrong? Here's the code of request handler

class ProblemsHandler(APIView):

    permission_classes = (
        IsOwnerOrReadOnly,
        permissions.IsAuthenticatedOrReadOnly,
    )

    def pre_save(self, request, problem):
        problem.author = request.user

    def get_object(self, request, pk, format):
        try:
            problem = ProblemsModel.objects.get(pk=pk)
            serializer = ProblemsSerializer(problem)
            return Response(serializer.data, status=HTTP_200_OK)
        except ProblemsModel.DoesNotExist:
            raise Http404

    def get_list(self, request, format):
        problems = ProblemsModel.objects.all()
        serializer = ProblemsSerializer(problems, many=True)
        return Response(serializer.data, status=HTTP_200_OK)

    def get(self, request, pk=None, format=None):
        if pk:
            return self.get_object(request, pk, format)
        else:
            return self.get_list(request, format)

    def post(self, request, format=None):
        serializer = ProblemsSerializer(data=request.DATA)
        if serializer.is_valid():
            self.pre_save(request, serializer.object)
            serializer.save()
            return Response(serializer.data, status=HTTP_201_CREATED)
        else:
            return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)

    def put(self, request, pk, format=None):
        try:
            problem = ProblemsModel.objects.get(pk=pk)
            serializer = ProblemsSerializer(problem, data=request.DATA)
            if serializer.is_valid():
                self.pre_save(request, serializer.object)
                serializer.save()
                return Response(serializer.data, status=HTTP_200_OK)
            else:
                return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
        except ProblemsModel.DoesNotExist:
            raise Http404

    def delete(self, request, pk, format=None):
        try:
            problem = ProblemsModel.objects.get(pk=pk)
            problem.delete()
            return Response(status=HTTP_204_NO_CONTENT)
        except ProblemsModel.DoesNotExist:
            raise Http404
like image 784
sbeliakov Avatar asked Mar 21 '14 14:03

sbeliakov


1 Answers

the permission-checks for objects are done by DRF in the method APIView.check_object_permissions.

Since you don't use the GenericAPIView, you define your own get_object method and you have to call check_object_permissions yourself. Since you are mis-using get_object a bit, you have to check for GET (single), PUT and DELETE

self.check_object_permissions(self.request, obj)

Perhaps have a better look at the DRF Generic Views, since your use-case looks much like them. Normally get_object should only return an object and check the permissions.

like image 131
Denis Cornehl Avatar answered Nov 15 '22 18:11

Denis Cornehl