0
votes

Comment puis-je empêcher un utilisateur authentifié de publier au nom de quelqu'un d'autre?

Si je suis connecté en tant que user1 et que j'accède à un ViewSet appelé RecipeSubmissionViewSet , le POST prend un recette_id de la recette que l'utilisateur souhaite soumettre. Comment puis-je m'assurer que user1 ne soumet pas la recette de user2 , en supposant que le modèle Recipe a un champ owner dessus et je peux simplement le comparer à request.user? Dois-je utiliser une classe d'autorisation pour cela ou y a-t-il un meilleur moyen? Je parle d'un point de vue backend et ne tient pas compte du fait que le front-end filtrerait bien sûr les recettes qui appartiennent à l'utilisateur et ne leur montrerait que leurs propres recettes.


1 commentaires

Pour plus de précisions, pouvez-vous inclure vos modèles et vues si possible?


3 Réponses :


0
votes

Utilisez-vous le système d'authentification django? Ensuite, vous devriez pouvoir accéder à request.user dans les vues et définir le champ owner en conséquence.

EDIT: Je pense que j'ai mal compris la question.

Mais cela pourrait aider et Nafees Anwar a l'air bien.


0 commentaires

2
votes

Il peut y avoir deux manières. Vous pouvez filtrer l'ensemble de requêtes ou définir une classe d'autorisation.

Si vous remplacez la méthode get_queryset comme ceci.

from rest_framework.permissions import BasePermission

class RecipeSubmissionPermission(BasePermission):
    def has_object_permission(self, request, view, obj):
        # you can also check permission here based on action
        # if view.action == 'update':
        #    pass
        return request.user.is_authenticated and obj.owner == request.user




class RecipeSubmissionViewSet(...):
    permission_classes=[RecipeSubmissionPermission]

L'utilisateur obtiendra 404 réponse et ne pourra jamais accéder à des objets autres que lui.

Le deuxième choix est la classe d'autorisation. Vous pouvez définir une classe d'autorisation personnalisée et vérifier explicitement la propriété de cette manière.

class RecipeSubmissionViewSet(...):
    def get_queryset(self):
        return Recipe.objects.filter(owner=self.request.user)
        # you can also use filtration based on action name like this

        # if self.action == 'update':
        #      return Recipe.objects.filter(owner=self.request.user)
        # return Recipe.objects.all()

Dans ce cas, l'utilisateur recevra une erreur d'autorisation 403 .

Si vous utilisez ces deux méthodes. 404 sera préféré.

Vous pouvez utiliser la méthode de votre choix ou les deux. La classe d'autorisation semble plus programmatique et structurée, mais l'utilisateur saura que l'objet avec cet identifiant existe mais il n'avait pas l'autorisation de le mettre à jour. Mais si vous remplacez le jeu de requêtes, l'utilisateur n'est même pas en mesure de savoir si l'objet existe ou n'est donc pas plus sécurisé.


7 commentaires

Merci d'avoir répondu. J'utilise en fait la méthode get_queryset , mais qu'en est-il sur un message? Qu'en est-il d'empêcher un utilisateur de publier la recette d'un autre utilisateur? Dois-je maintenant utiliser une classe d'autorisation ou puis-je en quelque sorte tirer parti du get_queryset dans un POST ?


Lorsque l'utilisateur publie pour mettre à jour une recette, get_queryset sera automatiquement utilisé pour obtenir l'instance de Recipe et tout le filtrage sera appliqué. Si vous effectuez la mise à jour manuellement (définissant des actions personnalisées), vous devez utiliser la méthode get_object pour obtenir l'instance Recipe que vous souhaitez mettre à jour. Il utilisera automatiquement la méthode get_queryset et retournera 404 si l'objet n'appartient pas à l'utilisateur.


La méthode get_queryset () n'a aucun rôle lors de la création d'objets. @NafeesAnwar


@JPG le POST prend une recette_id de la recette que l'utilisateur veut soumettre Je pense qu'il essaie de mettre à jour.


Non, j'essaye de créer.


@Pittfall Vous devriez ajouter quelques morceaux de code (ensemble de vues, modèles) si possible pour une réponse plus claire. Formez un anglais simple, il est difficile de comprendre exactement ce que vous essayez de faire.


Ok, disons que vous avez une Recipe , vous la postez parce que vous n'avez pas fini de l'écrire mais elle n'est PAS soumise dans le tableau RecipeSubmission . Ensuite, vous POST (créez) un RecipeSubmission et dans le corps de la vue RecipeSubmission attend un recette_id . Je ne veux pas que quelqu'un injecte une recette_id dans le corps de RecipeSubmission pour une Recipe qui n'appartient pas à cet utilisateur authentifié.



0
votes

La réponse de Nafees est à peu près la voie à suivre.

J'ai développé des microservices avec multi-location pour les utilisateurs et les règles pour eux (selon les spécifications de mes projets) sont:

  • Les utilisateurs ne peuvent pas créer d'éléments au nom d'une autre entreprise / utilisateur
  • Les utilisateurs ne peuvent pas afficher / modifier les éléments appartenant à une autre société.

La façon dont je fais cela est simple.

Pour interdire l'affichage / la modification des données de quelqu'un d'autre

class SomeSerializer(...):
    def validate(self, data):
        data.pop('user', None)
        data['user'] = self.context['request'].user

Et pour interdire la modification des choses de quelqu'un d'autre, cela se fait sur un sérialiseur

def get_queryset(self):
    return self.queryset.filter(user=request.user)

Avec ce qui précède, le get_queryset dans l'ensemble de vues renverra toujours un 404 si l'utilisateur1 demande des informations sur l'utilisateur2.

Et le La fonction de validation empêchera l'attribution. C'est à dire. Si user1 crée quelque chose assigné à user2, il attribuera plutôt user1, ce comportement est ce dont j'avais besoin dans mon application, vous pouvez toujours augmenter les sérialiseurs.ValidationError ("Vous ne pouvez pas assigner des choses à user2") à la place si c'est ce dont vous avez besoin au lieu de réaffecter l'utilisateur comme je le fais dans mon cas d'utilisation. Avec cette logique dans le valider , vous pouvez être sûr que toute fonction inscriptible aura toujours le même comportement pour ce sérialiseur.

J'espère que cela vous aidera.

p>


0 commentaires