【问题标题】:DRY-rest-permissions somehow does not check my object permissions except global permissionsDRY-rest-permissions 不检查我的对象权限,除了全局权限
【发布时间】:2021-09-20 14:30:24
【问题描述】:

我最近开始实施dry-rest-permissions,但我似乎无法检查has_object_permissions,看来只有全局权限对我有用。

我对实现权限还很陌生,这是我第一次实现 DRY-rest-permissions,并且最近才开始在 django rest 框架中编码,因此对于缺乏知识提前表示歉意。

目前我试图通过简单地让用户调用 URL 来删除公司对象,然后该 URL 获取当前用户的 active_company,然后仅当当前 useractive_company 时才将其删除scompany_owner

但我发现,我无法让has_object_permissions 在任何地方工作?

我注意到,如果我删除has_write_permission(request),然后点击company_delete URL,则会出现以下错误:

'<class 'company.models.Company'>' does not have 'has_write_permission' or 'has_company_delete_permission' defined.

这意味着它甚至不寻找has_object_company_delete_permission。这意味着它只检查全局权限而不是任何对象权限,我在这里可能做错了什么?

我的模特:

class Company(models.Model):
    company_name = models.CharField(max_length=100)
    company_orders = models.IntegerField(blank=True, null=True)
    company_icon = models.ImageField(
        upload_to='media/company_icon', blank=True)
    company_owner = models.ForeignKey(
        User, on_delete=models.SET_NULL, blank=True, null=True)
    company_employees = models.ManyToManyField(
        User, blank=True, null=True, related_name="company_employees")

    def __str__(self):
        return self.company_name

    @staticmethod
    def has_write_permission(request):
        return False

    def has_object_company_delete_permission(self, request):
        return self.company_owner == request.user

我的看法

class CompanyView(viewsets.ModelViewSet):  # made for viewing details
    permission_classes = (DRYPermissions, )
    queryset = Company.objects.all()
    serializer_class = CompanySerializer

    def create(self, request):
        try:

            company_name = request.data['company_name']
            company_orders = request.data['company_orders']
            company_owner = request.data['company_owner']
            company_owner_obj = User.objects.get(id=company_owner)
            company = Company(company_name=company_name,
                              company_orders=company_orders, company_owner=company_owner_obj)
            company.save()

        except Exception as error:
            response = {
                'error': str(error)
            }
            return Response(response, status=status.HTTP_400_BAD_REQUEST)

        response = {
            'message': 'Company created'
        }

        return Response(response, status=status.HTTP_201_CREATED)

    def company_details(self, request):
        try:
            company_id = request.user.active_company.id

            company = Company.objects.get(id=company_id)

            serialized_data = CompanySerializer(company)

        except Exception as error:
            response = {
                'error': str(error)
            }
            return Response(response)

        return Response(serialized_data.data)

    def company_edit(self, request, **kwargs):
        try:
            company_id = request.user.active_company.id
            company = Company.objects.get(id=company_id)
            serializer = CompanySerializer(
                company, data=request.data, partial=True)
            if serializer.is_valid():
                serializer.save()
        except Exception as error:
            response = {
                'message': str(error)
            }
            return Response(response)
        response = {
            'message': 'Edited Successfully'
        }
        return Response(response)

    def company_delete(self, request):
        try:
            company_id = request.user.active_company.id
            company = Company.objects.filter(id=company_id)
            company.delete()
        except Exception as error:
            response = {
                'message': str(error)
            }
            return Response(response)
        response = {
            'message': 'Deleted Successfully'
        }
        return Response(response)

我的网址

urlpatterns = [
    #    Company URLs
    path('company_create/',
         CompanyView.as_view({'post': 'create'}), name='company_create'),  # Create company
    path('company_edit/',
         CompanyView.as_view(), name='company_edit'),  # Edit company details
    path('company_delete/',
         CompanyView.as_view({'delete': 'company_delete'}), name='company_delete'),  # Delete company
    path('company_details/',
         CompanyView.as_view({'get': 'company_details'}), name='company_details'),  # get company details (owner, employees etc)
]

我的序列化器

class CompanySerializer(serializers.ModelSerializer):
    company_owner = LimitedUserSerializer(read_only=True)

    class Meta:
        model = Company
        fields = ['id', 'company_name', 'company_orders',
                  'company_icon', 'company_owner']

【问题讨论】:

    标签: django django-rest-framework permissions


    【解决方案1】:

    this part of the documentation 中所述,始终首先检查全局权限,仅当全局权限通过时才检查对象权限。

    文档来源:

    DRY Rest Permissions allows you to define both global and object level permissions.
    
    Global permissions are always checked first and define the ability of a user to take an action on an entire model. For example you can define whether a user has the ability to update any projects from the database.
    
    Object permissions are checked if global permissions pass and define whether a user has the ability to perform a specific action on a single object. These are also known as row level permissions. Note: list and create actions are the only standard actions that are only global. There is no such object level permission call because they are whole table actions.
    

    在这种情况下,您实际上有多个问题需要纠正:

    • 确保 has_write_permission 为所有拥有活跃公司的用户返回 True
    • 请务必重命名has_object_company_delete_permission,因为我们不需要函数名称中的模型名称

    例子:

       @staticmethod
       def has_write_permission(request):
           # Everybody can create/update/delete if no specific rule says otherwise
           return True
    
       def has_object_delete_permission(self, request):
           # Only owner can delete
           return self.company_owner == request.user
    
       def has_object_update_permission(self, request):
           # Only owner can update
           return self.company_owner == request.user
    

    输出:

    • 每个人都可以创造
    • 只有所有者才能更新
    • 只有所有者才能删除

    我知道仅仅删除一个对象似乎有点矫枉过正,但是根据一些经验,它可以让您清楚地定义 ans 设置权限,还可以通过使用 DryPermissionsField 和 @987654329 轻松地与前端共享通用规则@

    PS:这个答案来自my origin answer on Github,让人们可以从 StackOverFlow 轻松找到解决方案

    【讨论】:

      【解决方案2】:

      它似乎不检查我的任何自定义操作中的对象权限,因此在 get_object() 或自定义操作中添加以下检查可以解决此问题。

      self.check_object_permissions(self.request, obtainedObject)
      

      我的代码中的示例:

      @action(detail=True, methods=['patch'], pk=None)
      def company_edit(self, request, **kwargs):
          try:
              company_id = request.user.active_company.id
              company = Company.objects.get(id=company_id)
              serializer = CompanySerializer(
                  company, data=request.data, partial=True)
              self.check_object_permissions(self.request, company)
              if serializer.is_valid():
                  serializer.save()
          except Exception as error:
              response = {
                  'message': str(error)
              }
              return Response(response)
          response = {
              'message': 'Edited Successfully'
          }
          return Response(response)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-07-12
        • 2016-06-23
        • 2016-02-28
        • 2020-07-13
        • 1970-01-01
        • 1970-01-01
        • 2020-09-15
        • 1970-01-01
        相关资源
        最近更新 更多