【问题标题】:Django Rest framework Viewset Permissions "create" without "list"Django Rest框架视图集权限“创建”没有“列表”
【发布时间】:2017-01-16 10:47:24
【问题描述】:

我有以下视图集:

class ActivityViewSet(viewsets.ModelViewSet):
    queryset = Activity.objects.all()
    serializer_class = ActivitySerializer

    def get_permissions(self):
        if self.action in ['update','partial_update','destroy','list']:
            self.permission_classes = [permissions.IsAdminUser,]
        elif self.action in ['create']:
            self.permission_classes = [permissions.IsAuthenticated,]
        else :
            self.permission_classes = [permissions.AllowAny,]
        return super(self.__class__, self).get_permissions()

正如所见,我试图为经过身份验证的用户(不是管理员)允许“创建”方法而不允许“列表”。 奇怪的是,这个 Viewset 没有为 Authenticated 用户创建或列出。 我检查了一下,只是为了得出结论,下面的代码:

class RouteOrderingDetail(mixins.CreateModelMixin, 
                   mixins.RetrieveModelMixin, 
                   mixins.DestroyModelMixin,
                   mixins.UpdateModelMixin,
                   viewsets.GenericViewSet):
    queryset = RouteOrdering.objects.all()
    serializer_class = RouteOrderingSerializer

确实允许视图中存在创建但没有列表(但它对我不可用,因为我确实需要可用的列表选项。

希望问题很清楚。如有任何帮助,我们将不胜感激。

【问题讨论】:

  • 查看如何创建自定义权限django-rest-framework.org/api-guide/permissions/…
  • 我确实做了自定义权限,您可以在代码中清楚地看到。问题不止于此。
  • 您没有创建自定义权限类。您已经在视图集中编辑了 get_permissions 方法。自定义权限类将允许您根据 request.method 返回权限
  • 我将如何创建自定义权限类?我试过这样做,但没有找到任何例子。应该在哪里上课?我如何参考它?等
  • 我实际上是这样检查的——它也不允许。

标签: python django permissions django-rest-framework


【解决方案1】:

我意识到这已经得到解答,但想分享我的实现,以防它更适合 OPS 用例或其他人的:

from rest_framework.authentication import TokenAuthentication, SessionAuthentication
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.viewsets import ReadOnlyModelViewSet

from ..models import MyModel
from .serializers import MyModelSerializer


class ActionBasedPermission(AllowAny):
    """
    Grant or deny access to a view, based on a mapping in view.action_permissions
    """
    def has_permission(self, request, view):
        for klass, actions in getattr(view, 'action_permissions', {}).items():
            if view.action in actions:
                return klass().has_permission(request, view)
        return False


class MyModelViewSet(ReadOnlyModelViewSet):
    serializer_class = MyModelSerializer
    queryset = MyModel.objects.all()

    permission_classes = (ActionBasedPermission,)
    action_permissions = {
        IsAuthenticated: ['update', 'partial_update', 'destroy', 'list', 'create'],
        AllowAny: ['retrieve']
    }

    authentication_classes = (TokenAuthentication, SessionAuthentication)

希望这能帮助某人:)

【讨论】:

  • 效果很好 - APIView 存在问题,因为在您的循环 if view.action in actions: 中,对于 OPTIONS 查询,view.action 是 None 。我刚刚添加了 elif view.action is None: return True 以始终允许 OPTIONS 出现。您还需要至少将'metadata' 添加到您的IsAuthenticated 列表中。屏蔽OPTIONS有点奇怪。
【解决方案2】:

也许你可以试试这个:

class NotCreateAndIsAdminUser(permissions.IsAdminUser):
    def has_permission(self, request, view):
        return (view.action in ['update', 'partial_update', 'destroy', 'list'] 
                and super(NotCreateAndIsAdminUser, self).has_permission(request, view))


class CreateAndIsAuthenticated(permissions.IsAuthenticated):
    def has_permission(self, request, view):
        return (view.action == 'create'
                and super(CreateAndIsAuthenticated, self).has_permission(request, view))

class NotSafeMethodAndAllowAny(permissions.AllowAny)
    def has_permission(self, request, view):
        return (view.action is not in ['update', 'partial_update', 'destroy', 'list', 'create']
                and super(NotSafeMethodAndAllowAny, self).has_permission(request, view))


class ActivityViewSet(viewsets.ModelViewSet):
    queryset = Activity.objects.all()
    serializer_class = ActivitySerializer
    permission_classes = (NotCreateAndIsAdminUser, CreateAndIsAuthenticated, NotSafeMethodAndAllowAny)

    def create(self, request):
        pass

    def list(self, request):
        pass
    ....

参考:Allow separate permissions per View in ViewSet

另外,您可能想查看与您的问题非常相似的问题:Separate permissions per methods

你可以这样做:

class ActivityViewSet(viewsets.ModelViewSet):
    queryset = Activity.objects.all()
    serializer_class = ActivitySerializer

    def get_permissions(self):
        if self.action in ['update', 'partial_update', 'destroy', 'list']:
            # which is permissions.IsAdminUser 
            return request.user and request.user.is_staff
        elif self.action in ['create']:
            # which is permissions.IsAuthenticated
            return request.user and is_authenticated(request.user)             
        else :
            # which is permissions.AllowAny
            return True

【讨论】:

  • 我相信permission_classes装饰器只能用在功能视图上。
  • 还是不行。为列表添加权限类:“@permission_classes((IsAdmin,))”后,经过身份验证的用户将无法使用“创建”操作。
  • @idik 实际上, adamfc 的评论是正确的,对不起我的错误。事实证明你的想法是正确的,覆盖你的 def get_permissions() 方法。但是,您需要以稍微不同的方式实现它。
猜你喜欢
  • 1970-01-01
  • 2014-05-10
  • 2019-07-13
  • 2021-06-07
  • 2015-10-28
  • 1970-01-01
  • 2017-04-13
  • 2016-11-20
  • 2015-08-04
相关资源
最近更新 更多