【发布时间】:2016-02-01 02:28:36
【问题描述】:
这是我的视图集:
class PageViewSet(viewsets.ModelViewSet):
queryset = Page.objects.all()
serializer_class = PageSerializer
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly,)
def perform_create(self, serializer):
serializer.save(owner=self.request.user, location=self.request.user.userextended.location)
@detail_route(methods=['post'])
def add(self, request, pk=None):
try:
page = Page.objects.get(pk=pk)
except:
content = {'Page': ['The page you are trying to add no longer exists.']}
return Response(content, status=status.HTTP_400_BAD_REQUEST)
page.users.add(request.user)
return Response(status=status.HTTP_204_NO_CONTENT)
这是我的IsOwnerOrReadOnly 权限:
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Allow only the owner (and admin) of the object to make changes (i.e.
do PUT, PATCH, DELETE and POST requests. A user is an
owner of an object if the object has an attribute
called owner and owner is == request.user. If the
object is a User object or if the object does not have
an owner attribute, then return object == request.user.
"""
def has_permission(self, request, view):
print('In permission')
return True
def has_object_permission(self, request, view, obj):
print('In object level permission')
if request.method in permissions.SAFE_METHODS:
return True
if request.user.is_staff:
return True
try:
return obj.owner == request.user
except: # if obj does not have an owner property (e.g. users don't
# have owner properties).
return obj == request.user
问题是,即使我不是页面的所有者,我也可以作为经过身份验证的用户发布到add-detail。当我发出帖子请求时,它只打印两次In permission,从不打印In object level permission。我的问题是,既然它是一个 detail_route 并且显然使用了一个 {lookup} 对象(请参阅此处,它表明它正在使用一个对象:http://www.django-rest-framework.org/api-guide/routers/),那么权限类中的 has_object_permission() 函数为什么没有被叫?为什么只调用常规的has_permission() 函数?
我希望有人链接到一个文档,该文档验证即使是 detail_route,也只有 has_permission 被调用。
编辑:这不是 Django rest framework ignores has_object_permission 的副本,因为我使用的是继承自 GenericAPIView 的 ModelViewSet(如文档中所述:http://www.django-rest-framework.org/api-guide/viewsets/#modelviewset)。
【问题讨论】:
-
@Ivan 这不是您链接到的帖子的副本,因为我使用的是继承自 GenericAPIView 的 ModelViewSet(我还编辑了我的帖子以添加此信息)。
-
要点同在接受的答案中,由您在
add中调用check_object_permissions。 -
@Ivan 答案是:“对象的权限检查由 DRF 在 APIView.check_object_permissions 方法中完成。由于您不使用 GenericAPIView,因此您定义了自己的 get_object 方法并且您拥有自己调用 check_object_permissions。”但是,我确实使用它(我从它继承)并且对于我所有其他 PageViewSet 请求(PUT、PATCH 和 DELETE),
IsOwnerOrReadOnly的check_object_permissions被调用得非常好。只是它不适用于我的 detail_route 函数。想知道它是否在文档中说detail_route不使用对象级权限? -
这就是我想说的:检查权限的不是路由器。当您定义要路由到的操作时,如果您不使用
get_object,则由您调用check_object_permissions。我在您的add中没有看到它。 -
我会发布一个完整的答案。