104 votes

Comment enregistrer les utilisateurs dans le cadre REST de Django ?

Je suis en train de coder une API REST avec Cadre REST de Django . L'API sera le backend d'une application mobile sociale. Après avoir suivi le tutoriel, je peux sérialiser tous mes modèles et je suis capable de créer de nouvelles ressources et de les mettre à jour.

J'utilise AuthToken pour l'authentification.

Ma question est la suivante :

Une fois que j'ai le /users ressource, je veux que l'utilisateur de l'application puisse s'enregistrer. Donc, est-il préférable d'avoir une ressource séparée comme /register ou permettre à des utilisateurs anonymes de POSTER à /users une nouvelle ressource ?

De même, des conseils sur les autorisations seraient les bienvenus.

16voto

Tadej Krevh Points 244

@cpury ci-dessus a suggéré d'utiliser write_only_fields option. Cette option n'a toutefois pas fonctionné pour moi dans DRF 3.3.3.

Sur DRF 3.0 le site write_only_fields sur ModelSerializer a été déplacée vers PendingDeprecation et dans DRF 3.2 remplacé par un extra_kwargs plus générique :

extra_kwargs = {'password': {'write_only': True}}

10voto

yndolok Points 1043

Toutes les réponses données jusqu'à présent créent l'utilisateur, puis mettent à jour le mot de passe de l'utilisateur. Cela entraîne deux écritures dans la base de données. Pour éviter une écriture supplémentaire inutile dans la base de données, définissez le mot de passe de l'utilisateur avant de le sauvegarder :

from rest_framework.serializers import ModelSerializer

class UserSerializer(ModelSerializer):

    class Meta:
        model = User

    def create(self, validated_data):
        user = User(**validated_data)
        # Hash the user's password.
        user.set_password(validated_data['password'])
        user.save()
        return user

6voto

arnobpl Points 383

Bien qu'il existe de nombreuses réponses à cette question, aucune d'entre elles (à l'heure où j'écris ces lignes) n'aborde le problème de sécurité essentiel, à savoir la validation du mot de passe définie dans le document settings.AUTH_PASSWORD_VALIDATORS . Il est donc possible de créer un mot de passe comme '1' ce qui ne doit pas être acceptable. J'ai donc corrigé ce problème de sécurité majeur. Voici ma solution :

Dans serializers.py :

from django.contrib.auth import get_user_model
from django.contrib.auth.password_validation import validate_password
from rest_framework import serializers

class SignupSerializer(serializers.ModelSerializer):
    class Meta:
        model = get_user_model()
        fields = ['username', 'first_name', 'last_name', 'email', 'password', ]
        extra_kwargs = {
            'password': {'write_only': True}
        }

    def validate_password(self, value):
        validate_password(value)
        return value

    def create(self, validated_data):
        user = get_user_model()(**validated_data)

        user.set_password(validated_data['password'])
        user.save()

        return user

Dans views.py :

from rest_framework import mixins, viewsets
from rest_framework.permissions import AllowAny, IsAuthenticated

from . import forms, serializers

class SignupViewSet(mixins.CreateModelMixin,
                    viewsets.GenericViewSet):
    permission_classes = [AllowAny]
    serializer_class = serializers.SignupSerializer

Réponse de l'API :

Maintenant, si vous essayez avec un mot de passe simple comme '1' cette réponse sera renvoyée automatiquement :

{
    "password": [
        "This password is too short. It must contain at least 8 characters.",
        "This password is too common.",
        "This password is entirely numeric."
    ]
}

Dans le cas d'un mot de passe comme '12345678' la réponse est :

{
    "password": [
        "This password is too common.",
        "This password is entirely numeric."
    ]
}

De cette façon, le client final saura exactement quelles sont les autres conditions requises pour que le mot de passe soit valide.

5voto

Karan Kumar Points 1587

Un peu tard dans la soirée, mais cela pourrait aider quelqu'un qui ne veut pas écrire plus de lignes de code.

Nous pouvons utiliser le super pour y parvenir.

class UserSerializer(serializers.ModelSerializer):

    password = serializers.CharField(
          write_only=True,
    )

    class Meta:
       model = User
       fields = ('password', 'username', 'first_name', 'last_name',)

    def create(self, validated_data):
        user = super(UserSerializer, self).create(validated_data)
        if 'password' in validated_data:
              user.set_password(validated_data['password'])
              user.save()
        return user

5voto

Une implémentation basée sur le viewset de Python 3, Django 2 et Django REST Framework :

Dossier : serializers.py

from rest_framework.serializers import ModelSerializers
from django.contrib.auth import get_user_model

UserModel = get_user_model()

class UserSerializer(ModelSerializer):
    password = serializers.CharField(write_only=True)

    def create(self, validated_data):
        user = UserModel.objects.create_user(
            username=validated_data['username'],
            password=validated_data['password'],
            first_name=validated_data['first_name'],
            last_name=validated_data['last_name'],
        )
        return user

    class Meta:
        model = UserModel
        fields = ('password', 'username', 'first_name', 'last_name',)

Fichier vues.py :

from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import CreateModelMixin
from django.contrib.auth import get_user_model
from .serializers import UserSerializer

class CreateUserView(CreateModelMixin, GenericViewSet):
    queryset = get_user_model().objects.all()
    serializer_class = UserSerializer

Fichier urls.py

from rest_framework.routers import DefaultRouter
from .views import CreateUserView

router = DefaultRouter()
router.register(r'createuser', CreateUserView)

urlpatterns = router.urls

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X