[英]Django Rest Framework Permissions and Ownership
I have two simple models 我有两个简单的模型
class User(AbstractUser):
pass
class Vacation(Model):
id = models.AutoField(primary_key=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
I am not really sure what is the scalable way of doing user permissions for Django Rest Framework. 我不太确定对Django Rest Framework执行用户权限的可伸缩方式是什么。 In particular: 尤其是:
/vacation
endpoint, user would see a filtered list 在/vacation
端点上,用户将看到一个过滤列表 /vacation/$id
endpoint, user would get a 403
if not owner 在/vacation/$id
端点上,如果不是所有者,则用户将获得403
What is the best way to achieve this in a future-proof fashion. 以面向未来的方式实现此目标的最佳方法是什么。 Say if further down the line: 说是否更深入:
Thank you! 谢谢!
From the docs: 从文档:
Permissions in REST framework are always defined as a list of permission classes. REST框架中的权限始终定义为权限类列表。 Before running the main body of the view each permission in the list is checked. 在运行视图主体之前,将检查列表中的每个权限。 If any permission check fails an exceptions.PermissionDenied or exceptions.NotAuthenticated exception will be raised, and the main body of the view will not run. 如果任何权限检查失败,则将引发exceptions.PermissionDenied或exceptions.NotAuthenticated异常,并且视图主体将不运行。
REST framework permissions also support object-level permissioning. REST框架权限还支持对象级权限。 Object level permissions are used to determine if a user should be allowed to act on a particular object, which will typically be a model instance. 对象级别权限用于确定是否应允许用户对特定对象执行操作,该对象通常是模型实例。
For your current need you can define your own Permission class: 根据您当前的需要,您可以定义自己的Permission类:
class IsVacationOwner(permissions.BasePermission):
# for view permission
def has_permission(self, request, view):
return request.user and request.user.is_authenticated
# for object level permissions
def has_object_permission(self, request, view, vacation_obj):
return vacation_obj.owner.id == request.user.id
And add this permission to your view. 并将此权限添加到您的视图。 For example on a viewset: 例如,在视图集上:
class VacationViewSet(viewsets.ModelViewSet):
permission_classes = (IsVacationOwner,)
One thing is important to notice here, since you will respond with a filtered list for '/vacations'
, make sure you filter them using the request.user
. 这里要注意一件事,因为您将使用'/vacations'
的过滤列表进行响应,因此请确保使用request.user
对其进行过滤。 Because object level permission will not be applicable for lists. 因为对象级别权限将不适用于列表。
For performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects. 出于性能原因,返回对象列表时,通用视图不会自动将对象级别权限应用于查询集中的每个实例。
For your future requirement, you can always set the permissions conditionally with the help of get_permissions
method. 为了将来的需求,您始终可以在get_permissions
方法的帮助下get_permissions
设置权限。
class VacationViewSet(viewsets.ModelViewSet):
def get_permissions(self):
if self.action == 'list':
# vacations can be seen by anyone
# remember to remove the filter for list though
permission_classes = [IsAuthenticated]
# or maybe that special type of user you mentioned
# write a `IsSpecialUser` permission class first btw
permission_classes = [IsSpecialUser]
else:
permission_classes = [IsVacationOwner]
return [permission() for permission in permission_classes]
DRF has great documentation . DRF具有出色的文档 。 I hope this helps you to get started and helps you to approach different use cases according to your future needs. 我希望这可以帮助您入门,并可以帮助您根据将来的需求使用不同的用例。
I would suggest you to use drf-viewsets
link . 我建议您使用drf-viewsets
link 。 We are going to use vacation viewset
to do this work. 我们将使用vacation viewset
来完成这项工作。
from your_app.views import VacationViewSet
router.register('api/vacations/', VacationViewSet)
from rest_framework import serializers
from your_app.models import Vacation
class VacationSerializer(serializers.ModelSerializer):
class Meta:
model = Vacation
fields = ('id', 'owner',)
read_only_fields = ('id',)
Here we are going to overwrite viewset's
retrive and list method. 在这里,我们将覆盖viewset's
和list方法。 There are other possible way to do that but i like this most as i can able to see what is happening in code. 还有其他可能的方法,但是我最喜欢这种方法,因为我能够看到代码中正在发生的事情。 Django model viewset inherited link of drf-mixins
retrive and list method. 视图集中继承的Django模型链接的drf-mixins
retrive和列表的方法。
from rest_framework import viewsets, permissions, exceptions, status
from your_app.models import Vacation, User
from your_app.serializers import VacationSerializer
class VacationViewSet(viewsets.ModelViewSet):
queryset = Vacation.objects.all()
permission_classes = [IsAuthenticated]
serializer = VacationSerializer
# we are going to overwrite list and retrive
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
# now we are going to filter on user
queryset = queryset.filter(owner=self.request.user)
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
# not permitted check
if instance.owner is not self.request.user:
raise exceptions.PermissionDenied()
serializer = self.get_serializer(instance)
return Response(serializer.data)
Django rest framework provides in-build settings for this Django rest框架为此提供了内置设置
Just import the required permission and add it to you class variable permission_classes 只需导入所需的权限并将其添加到您的类变量permission_classes中
in my_name.api.views 在my_name.api.views中
from rest_framework.permissions import ( AllowAny, IsAuthenticated, IsAdminUser, IsAuthenticatedOrReadOnly,)
class Vacation(ListAPIView):
serializer_class = VacationListSerializer
permission_classes = [IsAuthenticated]
You can add multiple permission classes as a list 您可以将多个权限类别添加为列表
Furthur, in case this is not helpful, you can always filter the model objects as 此外,如果这样做没有帮助,您可以始终将模型对象过滤为
Mymodel.objects.filter(owner = self.request.user)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.