Django-rest-framework: Objektberechtigungen werden in benutzerdefinierten Viewset-Routen nicht überprüft

Erstellt am 23. Mai 2016  ·  4Kommentare  ·  Quelle: encode/django-rest-framework

Schritte zum Reproduzieren

class MyViewSet(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MySerializer
    authentication_classes = (MyAuth, )
    permission_classes = (MyPermissions, )

    @detail_route(methods=["GET", ])
    def custom(self, request, pk=None):
        return Response('whatever')

from rest_framework import routers
router = routers.SimpleRouter() 
router.register('mymodel', MyViewSet)
urlpatterns = [
    url(r'^api/', include(router.urls)),
]

eine GET-Anfrage an /api/mymodel/123/custom/ stellen

Erwartetes Verhalten

has_object_permission() sollte mit MyModel.objects.get(pk=123) als Objekt aufgerufen werden.

Tatsächliches Verhalten

Anfrage an die benutzerdefinierte Route in der Form /api/mymodel/123/custom/ ruft has_permission() in MyPermissions auf, aber nicht has_object_permission(), obwohl es sich um eine Detailroute handelt.

Documentation

Hilfreichster Kommentar

Wir müssen die Tatsache dokumentieren, dass Sie nur has_object_permission aufgerufen bekommen, wenn Sie get_object aufrufen.

Alle 4 Kommentare

Wir müssen die Tatsache dokumentieren, dass Sie nur has_object_permission aufgerufen bekommen, wenn Sie get_object aufrufen.

Dies erscheint kontraintuitiv. Aufrufe wie /api/object/123/method/ werden im Allgemeinen verwendet, um eine Methode für die Objektinstanz mit der ID 123 aufzurufen, und es scheint, dass die Überprüfung der Objektberechtigung ein erwartetes Verhalten wäre. Andernfalls müsste jedes Mal, wenn jemand benutzerdefinierte Detailrouten erstellt, das Objekt abgerufen, die Berechtigungen manuell überprüft und fortgefahren werden. An diesem Punkt macht der Aufruf von has_object_permission() sowieso keinen Sinn. In jedem Szenario, in dem Berechtigungen auf Objektebene verwendet werden, müsste also eine solche Boilerplate verwendet werden

class CustomPermission(BasePermission):
    def has_permission(self, request, view):
        """we need to do all permission checking here, since has_object_permission() is not guaranteed to be called"""
        if 'pk' in view.kwargs and view.kwargs['pk']:
            obj = view.get_queryset()[0]
            # check object permissions here
        else:
            # check model permissions here

    def has_object_permission(self, request, view, obj):
        """ nothing to do here, we already checked everything, so ignore """
        return True

Ich glaube, ich habe es jetzt verstanden. Wenn ich get_object() in meinen benutzerdefinierten Routen aufrufe, wird has_object_permission() aufgerufen. Scheint immer noch kontraintuitiv, aber zumindest gibt es eine klare Lösung.

Ich würde gerne einen konkreten Pull-Request für die Dokumentation in Betracht ziehen, aber so wie es aussieht, denke ich, dass das, was wir haben, in http://www.django-rest-framework.org/api-guide/permissions/ in etwa angemessen ist.

Abschließend _könnten_, wie bereits erwähnt, spezifische Umformulierungen/Ergänzungen in Betracht gezogen werden.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen