Django REST Framework - Separate permissions per methods

后端 未结 7 1976
栀梦
栀梦 2020-12-23 13:19

I am writing an API using Django REST Framework and I am wondering if can specify permissions per method when using class based views.

Reading the documentation I se

7条回答
  •  悲哀的现实
    2020-12-23 13:45

    Update 30 March 2020: My original solution only patched object permissions, not request permissions. I've included an update below to make this work with request permissions as well.

    I know this is an old question but I recently ran into the same problem and wanted to share my solution (since the accepted answer wasn't quite what I needed). @GDorn's answer put me on the right track, but it only works with ViewSets because of the self.action

    I've solved it creating my own decorator:

    def method_permission_classes(classes):
        def decorator(func):
            def decorated_func(self, *args, **kwargs):
                self.permission_classes = classes
                # this call is needed for request permissions
                self.check_permissions(self.request)
                return func(self, *args, **kwargs)
            return decorated_func
        return decorator
    

    Instead of setting the permission_classes property on the function, like the built-in decorator does, my decorator wraps the call and sets the permission classes on the view instance that is being called. This way, the normal get_permissions() doesn't need any changes, since that simply relies on self.permission_classes.

    To work with request permissions, we do need to call check_permission() from the decorator, because the it's orginally called in initial() so before the permission_classes property is patched.

    Note The permissions set through the decorator are the only ones called for object permissions, but for request permissions they are in addition to the class wide permissions, because those are always checked before the request method is even called. If you want to specify all permissions per method only, set permission_classes = [] on the class.

    Example use case:

    from rest_framework import views, permissions
    
    class MyView(views.APIView):
        permission_classes = (permissions.IsAuthenticatedOrReadOnly,)  # used for default APIView endpoints
        queryset = MyModel.objects.all()
        serializer_class = MySerializer
    
    
        @method_permission_classes((permissions.IsOwnerOfObject,))  # in addition to IsAuthenticatedOrReadOnly
        def delete(self, request, id):
            instance = self.get_object()  # ...
    

    Hope this helps someone running into the same problem!

提交回复
热议问题