我是使用Django + Django Rest-framework进行开发的新手,我正在开发一个提供REST Api访问的项目。我想知道为给定的ApiView或Viewset的每个动作分配不同的权限的最佳做法是什么。
假设我定义了一些权限类,例如'IsAdmin','IsRole1','IsRole2',...,我想为单个操作授予不同的权限(例如,具有Role1的用户可以创建或检索,具有Role2的用户可以更新,只有管理员可以删除。)
如何构建基于类的视图,以便为“创建”,“列表”,“检索”,“更新”,“删除”操作分配权限类? 我正在尝试这样做,以便可以为具有相同权限模式的不同表重用一个类。
也许我只是淹死在一寸水里,谢谢你的回复。
答案 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
,您可以访问request
和view
个对象。您可以检查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):