Django rest framework permission_classes of ViewSe

2019-01-25 15:24发布

I'm writing a rest API with the Django REST framework, and I'd like to protect certain endpoints with permissions. The permission classes look like they provide an elegant way to accomplish this. My problem is that I'd like to use different permission classes for different overridden ViewSet methods.

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    def create(self, request, *args, **kwargs):
        return super(UserViewSet, self).create(request, *args, **kwargs)

    @decorators.permission_classes(permissions.IsAdminUser)
    def list(self, request, *args, **kwargs):
        return super(UserViewSet, self).list(request, *args, **kwargs)

In the code above I'd like to allow registration (user creation) for unauthenticated users too, but I don't want to let list users to anyone, just for staff.

In the docs I saw examples for protecting API views (not ViewSet methods) with the permission_classes decorator, and I saw setting a permission classes for the whole ViewSet. But it seems not working on overridden ViewSet methods. Is there any way to only use them for certain endpoints?

2条回答
孤傲高冷的网名
2楼-- · 2019-01-25 15:28

I created a superclass that is derived from @ilse2005's answer. In all subsequent django views you can inherit this to achieve action level permission control.

class MixedPermissionModelViewSet(viewsets.ModelViewSet):
   '''
   Mixed permission base model allowing for action level
   permission control. Subclasses may define their permissions
   by creating a 'permission_classes_by_action' variable.

   Example:
   permission_classes_by_action = {'list': [AllowAny],
                                   'create': [IsAdminUser]}
   '''

   permission_classes_by_action = {}

   def get_permissions(self):
      try:
        # return permission_classes depending on `action`
        return [permission() for permission in self.permission_classes_by_action[self.action]]
      except KeyError:
        # action is not set return default permission_classes
        return [permission() for permission in self.permission_classes]
查看更多
不美不萌又怎样
3楼-- · 2019-01-25 15:39

I think there is no inbuilt solution for that. But you can achieve this by overriding the get_permissions method:

from rest_framework.permissions import AllowAny, IsAdminUser

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    permission_classes_by_action = {'create': [AllowAny],
                                    'list': [IsAdminUser]}

    def create(self, request, *args, **kwargs):
        return super(UserViewSet, self).create(request, *args, **kwargs)

    def list(self, request, *args, **kwargs):
        return super(UserViewSet, self).list(request, *args, **kwargs)

    def get_permissions(self):
        try:
            # return permission_classes depending on `action` 
            return [permission() for permission in self.permission_classes_by_action[self.action]]
        except KeyError: 
            # action is not set return default permission_classes
            return [permission() for permission in self.permission_classes]
查看更多
登录 后发表回答