是否有最佳实践为给定APIView
或的每个操作分配不同的权限ViewSet
?
假设我定义了一些权限类,例如“IsAdmin”、“IsRole1”、“IsRole2”……,并且我想为单个操作授予不同的权限(例如,具有 Role1 的用户可以创建或检索,具有Role2 可以更新,只有管理员可以删除)。
如何构建基于类的视图,以便将权限类分配给“创建”、“列表”、“检索”、“更新”、“删除”操作?我试图这样做是为了拥有一个可以重用于具有相同权限模式的不同表的类。
是否有最佳实践为给定APIView
或的每个操作分配不同的权限ViewSet
?
假设我定义了一些权限类,例如“IsAdmin”、“IsRole1”、“IsRole2”……,并且我想为单个操作授予不同的权限(例如,具有 Role1 的用户可以创建或检索,具有Role2 可以更新,只有管理员可以删除)。
如何构建基于类的视图,以便将权限类分配给“创建”、“列表”、“检索”、“更新”、“删除”操作?我试图这样做是为了拥有一个可以重用于具有相同权限模式的不同表的类。
在 DRF 文档中,
注意:实例级别的 has_object_permission 方法只有在视图级别的 has_permission 检查已经通过时才会被调用
让我们假设以下关于user
对象的权限
permissons.py
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
views.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,)
对于 Django 2.0 替换is_authenticated()
为is_authenticated
. 该方法已变成一个属性。
您可以创建自定义权限类扩展 DRF 的BasePermission
.
您has_permission
在可以访问request
和view
对象的地方实现。您可以检查request.user
适当的角色并根据需要返回True
/ False
。
看看提供的IsAuthenticatedOrReadOnly类(和其他类),看看它是多么容易的一个很好的例子。
我希望这会有所帮助。
我个人很讨厌弗兰肯斯坦这种怪物般的自定义权限,在我看来,当涉及到 Django 框架时,它并不是很地道。
所以我想出了以下解决方案——它@list_route
与@detail_route
装饰器的工作方式非常相似。我们依赖于方法/函数是一流对象的事实
首先,我正在创建这样的装饰器:
装饰器.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 列表传递的参数
现在我创建了这样的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
当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):
Django 有一个名为的权限类DjangoObjectPermissions
,它使用 Django Guardian 作为身份验证后端。
当您在设置中激活 Django 监护人时,您只需将其添加permission_classes = [DjandoObjectPermissions]
到您的视图中,它会自动进行权限验证,因此您可以根据对特定django.contrib.auth
组或用户设置的权限进行“CRUD”。
请参阅带有示例的要点。
您可以将Django Guardian设置为您的身份验证支持
RestFramework 的基于类的视图对每个 HTTP 动词都有方法(即:HTTP GET =>view.get()
等)。您只需要使用django.contrib.auth
文档中的权限、用户、组和装饰器。