has_object_permission 和 has_permission 有什么区别?

What's the differences between has_object_permission and has_permission?

我对 Django-rest-framework 中的BasePermission感到困惑。

这里我定义了一个class:IsAuthenticatedAndOwner.

class IsAuthenticatedAndOwner(BasePermission):
    message = 'You must be the owner of this object.'
    def has_permission(self, request, view):
        print('called')
        return False
    def has_object_permission(self, request, view, obj):
        # return obj.user == request.user
        return False

views.py

中使用
class StudentUpdateAPIView(RetrieveUpdateAPIView):
    serializer_class = StudentCreateUpdateSerializer
    queryset = Student.objects.all()
    lookup_field = 'pk'
    permissions_classes = [IsAuthenticatedAndOwner]

但它根本不起作用。大家可以通过权限,更新数据。

未打印 called


我曾经这样定义class:IsNotAuthenticated

class IsNotAuthenticated(BasePermission):
    message = 'You are already logged in.'
    def has_permission(self, request, view):
        return not request.user.is_authenticated()

在函数中效果很好

class UserCreateAPIView(CreateAPIView):
    serializer_class = UserCreateSerializer
    queryset = User.objects.all()
    permission_classes = [IsNotAuthenticated]

那么,上面的例子和函数 has_object_permission & has_permission 有什么区别?

基本上,第一个代码否定了一切,因为 has_permission return False.

has_permission 是在调用 has_object_permission 之前进行的检查。这意味着您 需要 得到 has_permission 的允许,然后才有机会检查所有权测试。

你想要的是:

class IsAuthenticatedAndOwner(BasePermission):
    message = 'You must be the owner of this object.'
    def has_permission(self, request, view):
        return request.user and request.user.is_authenticated
    def has_object_permission(self, request, view, obj):
        return obj.user == request.user

这也将允许经过身份验证的用户创建新项目或列出它们。

我们在BasePermissionclass上有以下两种权限方式:

  • def has_permission(self, request, view)
  • def has_object_permission(self, request, view, obj)

这两种不同的方法要求限制未经授权的用户进行数据插入和操作。

has_permission 在所有 HTTP 请求上调用,而 has_object_permission 从 DRF 的方法 def get_object(self) 调用。因此,has_object_permission 方法可用于 GETPUTDELETE,不适用于 POST 请求。

总结:

  • permission_classes 遍历定义的列表。
  • has_object_permission 方法在 has_permission 方法之后被调用 returns 值 True 除了在 POST 方法中(仅在 POST 方法中 has_permission 被执行)。
  • permission_classes方法返回False值时,请求没有权限,不会再循环,否则,它会在循环时检查所有权限。
  • has_permission 方法将在所有 (GET, POST, PUT, DELETE) HTTP 请求上调用。
  • has_object_permission 方法不会在 HTTP POST 请求中被调用,因此我们需要从 has_permission 方法中限制它。

我认为这可以帮助:

class IsAuthorOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        # Read-only permissions are allowed for any request
        if request.method in permissions.SAFE_METHODS:
            return True
        # Write permissions are only allowed to the author of a post
        return obj.user == request.user