2016-11-14 107 views
1

使用ModelViewSet和DjangoObjectPermissions。在Django rest框架中創建之前檢查對象權限

Django REST框架似乎不會爲「創建」請求(POST)調用check_object_permission。 我需要檢查用戶被允許創建THIS對象之前它被保存到數據庫(因爲權限檢查取決於對象值)

我想我需要重寫ModelViewSet的「創建」方法,但我不知道如何從串行器獲取實例而不保存到數據庫。

  1. 如何從串行器中獲取對象實例而不保存到數據庫?
  2. 或者如何讓DRF檢查POST /創建請求的對象權限?

感謝

編輯:

進一步深化閩臺到DRF代碼後,我能夠獲得實例不保存:

def create(self, request, *args, **kwargs): 
    serializer = WorkedHourSerializer(data=request.data) 
    if serializer.is_valid(): 
     instance = MyModel(**serializer.validated_data) 

但Django的拒絕檢查燙髮的對象沒有主鍵所以我必須強制一個:

 instance.id = 0 
     self.check_object_permissions(request, instance) 
+0

哪裏'check_object_permissions '從哪裏來?你用這個庫嗎? – DanEEStar

+0

它來自REST框架API:http://www.django-rest-framework.org/api-guide/permissions/#object-level-permissions –

回答

0
  1. 有沒有辦法保存前獲得實例(see more

  2. 最好的辦法似乎是實現一個自定義的權限(可能繼承rest_framework.permissions.BasePermissionrest_framework.permissions.IsAuthenticated)和添加權限在has_permission(self, request, view)檢查邏輯(see more)。這樣,您將訪問request.user,然後您將能夠確定該用戶是否有權創建該對象。

+0

問題是更通用的,在更新請求中,'check_object_permission'是在'get_object'中調用,它使用數據庫中的對象版本而不是客戶端發送的數據。所以我寫了一個Mixin應用於ModelViewSet,它在客戶端發送的對象上執行check_object_permission,並保存到數據庫之前(見下文) –

1

我的解決方案是創建一個混合到上ModelViewSet與創建的實例執行check_object_permission申請使用request.data而不是對象從數據庫中檢索到的數據被保存到數據庫中之前:

import uuid 


class CheckObjectPermissionBeforeSaveMixin(): 

    def create(self, request, *args, **kwargs): 
     self.check_instance_from_data_permission(request) 
     return super(CheckObjectPermissionBeforeSaveMixin, self).create(request, *args, **kwargs) 

    def update(self, request, *args, **kwargs): 
     self.check_instance_from_data_permission(request) 
     return super(CheckObjectPermissionBeforeSaveMixin, self).update(request, *args, **kwargs) 

    def destroy(self, request, *args, **kwargs): 
     self.check_instance_from_data_permission(request) 
     return super(CheckObjectPermissionBeforeSaveMixin, self).destroy(request, *args, **kwargs) 

    def check_instance_from_data_permission(self, request): 
     instance = self.get_instance_from_data(request.data) 
     if instance: 
      self.check_object_permissions(request, instance) 

    def get_instance_from_data(self, data): 
     ModelClass = self.serializer_class.Meta.model 
     serializer = self.get_serializer(data=data) 
     if serializer.is_valid(): 
      instance = ModelClass(**serializer.validated_data) 
      instance.id = data.get('id') or uuid.uuid4().hex # Django's has_perm need a primary key to be set... 
      return instance 
     return None 


class MyModelViewSet(CheckObjectPermissionBeforeSaveMixin, viewsets.ModelViewSet): 
    queryset = MyModel.objects.all() 
    serializer_class = MyModelSerializer 
0

我認爲這是一個巨大的安全缺陷。確保它的另一種方式 - 如果沒有產生很好的HTML響應是編寫一個自定義的模型序列,如果你使用它和REST API查看/ ViewSets和使用對象級權限:

class CreatePermModelSerializer(ModelSerializer): 
def create(self, validated_data): 
    obj = self.Meta.model(**validated_data) 
    view = self._context['view'] 
    request = self._context['request'] 
    for permission in view.permission_classes: 
     if not permission.has_object_permission(self, request, view, obj): 
      raise ValueError('not authorized') 
    super(CreatePermModelSerializer, self).create(validated_data) 
相關問題