J'écris une API en utilisant Django REST Framework et je me demande si peut spécifier des autorisations par méthode lors de l'utilisation des vues basées sur les classes).
Lire la documentation Je vois que c'est assez facile à faire si vous écrivez des vues basées sur des fonctions, en utilisant simplement le @permission_classes
décorateur sur la fonction des vues que vous souhaitez protéger avec des autorisations. Cependant, je ne vois pas de moyen de faire la même chose lors de l'utilisation de CBV avec la classe APIView
, car alors je spécifie les autorisations pour la classe complète avec le permission_classes
, mais qui sera ensuite appliqué à toutes les méthodes de classe (get
, post
, put
...).
Ainsi, est-il possible d'avoir les vues API écrites avec des CBV et de spécifier également des autorisations différentes pour chaque méthode d'une classe de vue?
Les autorisations sont appliquées à l'ensemble de la classe View, mais vous pouvez prendre en compte des aspects de la demande (comme la méthode telle que GET ou POST) dans votre décision d'autorisation.
Voyez le IsAuthenticatedOrReadOnly
intégré comme exemple:
SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS']
class IsAuthenticatedOrReadOnly(BasePermission):
"""
The request is authenticated as a user, or is a read-only request.
"""
def has_permission(self, request, view):
if (request.method in SAFE_METHODS or
request.user and
request.user.is_authenticated()):
return True
return False
J'ai rencontré le même problème lors de l'utilisation de CBV, car j'ai une logique d'autorisations assez complexe en fonction de la méthode de demande.
La solution que j'ai trouvée a été d'utiliser l'application tierce 'rest_condition' listée au bas de cette page
http://www.Django-rest-framework.org/api-guide/permissions
https://github.com/caxap/rest_condition
Je viens de diviser la logique du flux d'autorisations afin que chaque branche s'exécute, selon la méthode de demande.
from rest_condition import And, Or, Not
class MyClassBasedView(APIView):
permission_classes = [Or(And(IsReadOnlyRequest, IsAllowedRetrieveThis, IsAllowedRetrieveThat),
And(IsPostRequest, IsAllowedToCreateThis, ...),
And(IsPutPatchRequest, ...),
And(IsDeleteRequest, ...)]
Ainsi, le "Ou" détermine quelle branche des autorisations doit s'exécuter en fonction de la méthode de demande et le "Et" encapsule les autorisations relatives à la méthode de demande acceptée, donc tous doivent passer pour que l'autorisation soit accordée. Vous pouvez également mélanger "Ou", "Et" et "Non" dans chaque flux pour créer des autorisations encore plus complexes.
Les classes d'autorisation pour exécuter chaque branche ressemblent simplement à ceci,
class IsReadyOnlyRequest(permissions.BasePermission):
def has_permission(self, request, view):
return request.method in permissions.SAFE_METHODS
class IsPostRequest(permissions.BasePermission):
def has_permission(self, request, view):
return request.method == "POST"
... #You get the idea
J'ai rencontré ce problème et je voulais vraiment utiliser le @permission_classes
décorateur pour marquer certaines méthodes d'affichage personnalisées avec des autorisations spécifiques. J'ai fini par trouver un mixin:
class PermissionsPerMethodMixin(object):
def get_permissions(self):
"""
Allows overriding default permissions with @permission_classes
"""
view = getattr(self, self.action)
if hasattr(view, 'permission_classes'):
return [permission_class() for permission_class in view.permission_classes]
return super().get_permissions()
Un exemple d'utilisation:
from rest_framework.decorators import action, permission_classes # other imports elided
class MyViewset(PermissionsPerMethodMixin, viewsets.ModelViewSet):
permission_classes = (IsAuthenticatedOrReadOnly,) # used for default ViewSet endpoints
queryset = MyModel.objects.all()
serializer_class = MySerializer
@action(detail=False, methods=['get'])
@permission_classes((IsAuthenticated,)) # overrides IsAuthenticatedOrReadOnly
def search(self, request):
return do_search(request) # ...