Django rest-framework每个动作权限

时间:2013-10-11 08:09:48

标签: python django django-rest-framework django-permissions

我是使用Django + Django Rest-framework进行开发的新手,我正在开发一个提供REST Api访问的项目。我想知道为给定的ApiView或Viewset的每个动作分配不同的权限的最佳做法是什么。

假设我定义了一些权限类,例如'IsAdmin','IsRole1','IsRole2',...,我想为单个操作授予不同的权限(例如,具有Role1的用户可以创建或检索,具有Role2的用户可以更新,只有管理员可以删除。)

如何构建基于类的视图,以便为“创建”,“列表”,“检索”,“更新”,“删除”操作分配权限类? 我正在尝试这样做,以便可以为具有相同权限模式的不同表重用一个类。

也许我只是淹死在一寸水里,谢谢你的回复。

5 个答案:

答案 0 :(得分:42)

在DRF文档中,

  

注意:只有在已经通过了视图级别的has_permission检查时才会调用实例级别的has_object_permission方法

我们假设关于from rest_framework import permissions class UserPermission(permissions.BasePermission): def has_permission(self, request, view): if view.action == 'list': return request.user.is_authenticated() and request.user.is_admin elif view.action == 'create': return True elif view.action in ['retrieve', 'update', 'partial_update', 'destroy']: return True else: return False def has_object_permission(self, request, view, obj): # Deny actions on objects if the user is not authenticated if not request.user.is_authenticated(): return False if view.action == 'retrieve': return obj == request.user or request.user.is_admin elif view.action in ['update', 'partial_update']: return obj == request.user or request.user.is_admin elif view.action == 'destroy': return request.user.is_admin else: return False 对象

的以下权限
  • 列表:仅限员工
  • 创建:任何人
  • 检索:拥有自己或员工
  • 更新,部分更新:拥有自己或员工
  • 销毁:仅限员工

permissons.py

from .models import User
from .permissions import UserPermission
from .serializers import UserSerializer
from rest_framework import viewsets


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

views.py

is_authenticated()

修改

对于Django 2.0,将is_authenticated替换为library(stringr) a[str_detect(a, '^.{6,}$')] #[1] "sdfdfdf" "dfdfdfd" 。该方法已变为属性。

答案 1 :(得分:15)

您可以创建custom permission class扩展DRF的BasePermission

您实施has_permission,您可以访问requestview个对象。您可以检查request.user是否有相应的角色,并根据需要返回True / False

查看提供的IsAuthenticatedOrReadOnly课程(和其他人),了解它是多么容易的好例子。

我希望有所帮助。

答案 2 :(得分:4)

Django有一个名为DjangoObjectPermissions的persmissions类,它使用Django Guardian作为身份验证后端。

当您的设置中有Django监护人激活时,您只需将permission_classes = [DjandoObjectPermissions]添加到您的视图中,它就会自动执行权限身份验证,因此您可以根据为特定django.contrib.auth组设置的权限进行'CRUD'或用户。

通过示例查看gist

您可以将Django Guardian设置为您的身份验证支持http://django-guardian.readthedocs.org/en/latest/installation.html

答案 3 :(得分:2)

RestFramework的基于类的视图具有每个HTTP谓词的方法(即:HTTP GET => view.get()等)。您只需使用django.contrib.auth的权限,用户,组和装饰器。

答案 4 :(得分:2)

我个人讨厌这种frankenmonster自定义权限,在我看来,当谈到Django框架时,它并不是非常惯用的; 所以我提出了以下解决方案 - 它与@list_route@detail_route装饰器的工作方式非常相似。 我们依赖于方法/函数是第一类对象的事实

首先,我正在创建这样的装饰器:

decorators.py

def route_action_arguments(**kwargs):
    """
    Add arguments to the action method
    """
    def decorator(func):
        func.route_action_kwargs = kwargs
        return func
    return decorator

正如您所看到的,它为函数添加了一个字典,它使用作为arg list传递的参数进行装饰

现在我创建了这样的mixin: mixins.py

class RouteActionArgumentsMixin (object):
    """
    Use action specific parameters to 
    provide:
    - serializer
    - permissions
    """

    def _get_kwargs(self):
        action = getattr(self, 'action')
        if not action:
            raise AttributeError
        print('getting route kwargs for action:' + action)
        action_method = getattr(self, action)
        kwargs = getattr(action_method, 'route_action_kwargs')
        print(dir(kwargs))
        return kwargs

    def get_serializer_class(self):
        try:
            kwargs = self._get_kwargs()
            return kwargs['serializer']
        except (KeyError, AttributeError):
            return super(RouteActionArgumentsMixin, self).get_serializer_class()

    def get_permissions(self):
        try:
            kwargs = self._get_kwargs()
            return kwargs['permission_classes']
        except (KeyError, AttributeError):
            return super(RouteActionArgumentsMixin, self).get_permissions()
Mixin做了两件事; 调用get_permissions时,会检查执行的“操作”,并查找与route_action_kwargs

关联的viewset.action_method.route_action_kwargs中的permission_classes集合

调用get_serializer_class时,它会执行相同操作并从serializer

中选择route_action_kwargs

现在我们可以使用它的方式:

@method_decorator(route_action_arguments(serializer=LoginSerializer), name='create')
class UserViewSet (RouteActionArgumentsMixin, RequestContextMixin, viewsets.ModelViewSet):
    """
    User and profile managment viewset
    """

    queryset = User.objects.all()
    serializer_class = UserSerializer

    @list_route(methods=['post'])
    @route_action_arguments(permission_classes=(AllowAny,), serializer=LoginSerializer)
    def login(self, request):
        serializer = self.get_serializer_class()(data=request.data)

对于我们明确定义的自定义路径,我们可以在方法上明确设置@route_action_arguments

在通用视图集和方法方面,我们仍然可以使用 @method_decorator

@method_decorator(route_action_arguments(serializer=LoginSerializer), name='create')
class UserViewSet (RouteActionArgumentsMixin, RequestContextMixin, viewsets.ModelViewSet):