簡體   English   中英

Django Rest框架的權限和所有權

[英]Django Rest Framework Permissions and Ownership

我有兩個簡單的模型

class User(AbstractUser): 
    pass


class Vacation(Model):
    id    = models.AutoField(primary_key=True)
    owner = models.ForeignKey(User, on_delete=models.CASCADE)

我不太確定對Django Rest Framework執行用戶權限的可伸縮方式是什么。 尤其是:

  • 用戶只能看到自己的假期
  • /vacation端點上,用戶將看到一個過濾列表
  • /vacation/$id端點上,如果不是所有者,則用戶將獲得403
  • 只要用戶是該對象的所有者(通過外鍵),他們就只能創建/更新休假

以面向未來的方式實現此目標的最佳方法是什么。 說是否更深入:

  • 我添加了其他用戶類型,該用戶類型可以查看所有假期,但只能創建/更新/刪除自己的假期
  • 我添加了另一個模型,用戶可以在其中讀取但不能寫入

謝謝!

從文檔:

REST框架中的權限始終定義為權限類列表。 在運行視圖主體之前,將檢查列表中的每個權限。 如果任何權限檢查失敗,則將引發exceptions.PermissionDenied或exceptions.NotAuthenticated異常,並且視圖主體將不運行。

REST框架權限還支持對象級權限。 對象級別權限用於確定是否應允許用戶對特定對象執行操作,該對象通常是模型實例。

根據您當前的需要,您可以定義自己的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

並將此權限添加到您的視圖。 例如,在視圖集上:

class VacationViewSet(viewsets.ModelViewSet):
    permission_classes = (IsVacationOwner,)

這里要注意一件事,因為您將使用'/vacations'的過濾列表進行響應,因此請確保使用request.user對其進行過濾。 因為對象級別權限將不適用於列表。

出於性能原因,返回對象列表時,通用視圖不會自動將對象級別權限應用於查詢集中的每個實例。

為了將來的需求,您始終可以在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具有出色的文檔 我希望這可以幫助您入門,並可以幫助您根據將來的需求使用不同的用例。

我建議您使用drf-viewsets link 我們將使用vacation viewset來完成這項工作。

我們的urls.py

from your_app.views import VacationViewSet
router.register('api/vacations/', VacationViewSet)

我們的serializers.py

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',)

我們的views.py

在這里,我們將覆蓋viewset's和list方法。 還有其他可能的方法,但是我最喜歡這種方法,因為我能夠看到代碼中正在發生的事情。 視圖集中繼承的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框架為此提供了內置設置

只需導入所需的權限並將其添加到您的類變量permission_classes中

my_name.api.views中

from rest_framework.permissions import ( AllowAny, IsAuthenticated, IsAdminUser, IsAuthenticatedOrReadOnly,)

class Vacation(ListAPIView):
    serializer_class = VacationListSerializer
    permission_classes = [IsAuthenticated]

您可以將多個權限類別添加為列表

此外,如果這樣做沒有幫助,您可以始終將模型對象過濾為

Mymodel.objects.filter(owner = self.request.user)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM