Maison > développement back-end > Tutoriel Python > Implémentation de vérification de numéro de téléphone dans un projet drf

Implémentation de vérification de numéro de téléphone dans un projet drf

Mary-Kate Olsen
Libérer: 2024-12-28 10:17:10
original
135 Les gens l'ont consulté

Implémentation de vérification de numéro de téléphone dans un projet drf

Pour implémenter un système de vérification de numéro de téléphone avec Django REST Framework (DRF), vous pouvez suivre les étapes suivantes. Ce système permettra aux utilisateurs de fournir leur numéro de téléphone, de recevoir un code de vérification par SMS (par exemple via Twilio), et de valider ce code pour vérifier leur numéro.

Étapes Principales :

  1. Installer les dépendances nécessaires
  2. Modifier le modèle utilisateur pour inclure le numéro de téléphone
  3. Créer un modèle pour stocker les codes de vérification
  4. Configurer un service d'envoi de SMS (ex. Twilio)
  5. Créer des sérialiseurs DRF
  6. Créer des vues et des routes API
  7. Gérer la logique de vérification et la sécurité

1. Installer les Dépendances Nécessaires

Tout d'abord, assurez-vous d'avoir installé les bibliothèques nécessaires :

  • Django REST Framework : Si ce n'est pas déjà fait.
  • Twilio : Pour l'envoi de SMS.
  • django-phonenumber-field : Pour la validation et le formatage des numéros de téléphone.

Installez-les via pip :

pip install djangorestframework twilio django-phonenumber-field
Copier après la connexion
Copier après la connexion

Ajoutez phonenumber_field et rest_framework à votre INSTALLED_APPS dans settings.py :

# settings.py

INSTALLED_APPS = [
    # ...
    'rest_framework',
    'phonenumber_field',
    # ...
]
Copier après la connexion
Copier après la connexion

2. Modifier le Modèle Utilisateur pour Inclure le Numéro de Téléphone

Si vous utilisez un modèle utilisateur personnalisé, ajoutez un champ pour le numéro de téléphone et un indicateur de vérification.

# models.py

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.db import models
from phonenumber_field.modelfields import PhoneNumberField

class UserManager(BaseUserManager):
    def create_user(self, email, username, phone_number, password=None):
        if not email:
            raise ValueError('Les utilisateurs doivent avoir une adresse email')
        if not phone_number:
            raise ValueError('Les utilisateurs doivent avoir un numéro de téléphone')

        user = self.model(
            email=self.normalize_email(email),
            username=username,
            phone_number=phone_number,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, username, phone_number, password=None):
        user = self.create_user(
            email,
            username,
            phone_number,
            password=password,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user

class CustomUser(AbstractBaseUser):
    email = models.EmailField(verbose_name='adresse email', max_length=255, unique=True)
    username = models.CharField(max_length=50, unique=True)
    phone_number = PhoneNumberField(unique=True, null=False, blank=False)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)
    is_phone_verified = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username', 'phone_number']

    def __str__(self):
        return self.email

    @property
    def is_staff(self):
        return self.is_admin
Copier après la connexion
Copier après la connexion

Remarque : Si vous avez déjà un modèle utilisateur, assurez-vous d'ajouter le champ phone_number et is_phone_verified de manière appropriée.

3. Créer un Modèle pour Stocker les Codes de Vérification

Ce modèle stockera les codes de vérification envoyés aux utilisateurs.

# models.py

import random
import string
from django.utils import timezone
from datetime import timedelta

class PhoneVerification(models.Model):
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='phone_verifications')
    code = models.CharField(max_length=6)
    created_at = models.DateTimeField(auto_now_add=True)
    is_verified = models.BooleanField(default=False)

    def is_expired(self):
        return self.created_at < timezone.now() - timedelta(minutes=10)  # Expire après 10 minutes

    def __str__(self):
        return f"Vérification de {self.user.email} - {'Validé' if self.is_verified else 'En attente'}"
Copier après la connexion
Copier après la connexion

4. Configurer un Service d'Envoi de SMS (Ex. Twilio)

Vous pouvez utiliser Twilio pour envoyer des SMS. Commencez par créer un compte Twilio et obtenir les identifiants nécessaires (ACCOUNT_SID, AUTH_TOKEN, FROM_NUMBER).

Ajoutez ces configurations à votre settings.py :

# settings.py

TWILIO_ACCOUNT_SID = 'votre_account_sid'
TWILIO_AUTH_TOKEN = 'votre_auth_token'
TWILIO_FROM_NUMBER = '+1234567890'  # Numéro Twilio
Copier après la connexion
Copier après la connexion

Créez un fichier utils.py pour gérer l'envoi de SMS :

# utils.py

from django.conf import settings
from twilio.rest import Client

def send_sms(to, message):
    client = Client(settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN)
    message = client.messages.create(
        body=message,
        from_=settings.TWILIO_FROM_NUMBER,
        to=str(to)
    )
    return message.sid
Copier après la connexion
Copier après la connexion

5. Créer des Sérialiseurs DRF

Créez des sérialiseurs pour gérer la demande de vérification et la validation du code.

pip install djangorestframework twilio django-phonenumber-field
Copier après la connexion
Copier après la connexion

6. Créer des Vues et des Routes API

Créez des vues pour gérer les demandes de vérification et la validation des codes.

# settings.py

INSTALLED_APPS = [
    # ...
    'rest_framework',
    'phonenumber_field',
    # ...
]
Copier après la connexion
Copier après la connexion

Remarque : Vous pourriez ajuster ces vues selon vos besoins, notamment si vous souhaitez créer un utilisateur lors de la vérification ou gérer différemment les utilisateurs existants.

7. Configurer les Routes API

Ajoutez les routes correspondantes dans votre urls.py.

# models.py

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.db import models
from phonenumber_field.modelfields import PhoneNumberField

class UserManager(BaseUserManager):
    def create_user(self, email, username, phone_number, password=None):
        if not email:
            raise ValueError('Les utilisateurs doivent avoir une adresse email')
        if not phone_number:
            raise ValueError('Les utilisateurs doivent avoir un numéro de téléphone')

        user = self.model(
            email=self.normalize_email(email),
            username=username,
            phone_number=phone_number,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, username, phone_number, password=None):
        user = self.create_user(
            email,
            username,
            phone_number,
            password=password,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user

class CustomUser(AbstractBaseUser):
    email = models.EmailField(verbose_name='adresse email', max_length=255, unique=True)
    username = models.CharField(max_length=50, unique=True)
    phone_number = PhoneNumberField(unique=True, null=False, blank=False)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)
    is_phone_verified = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username', 'phone_number']

    def __str__(self):
        return self.email

    @property
    def is_staff(self):
        return self.is_admin
Copier après la connexion
Copier après la connexion

8. Ajouter des Logiques Supplémentaires (Optionnel)

a. Génération de Code Unique par Utilisateur

Modifiez la vue de demande pour associer le code à un utilisateur spécifique ou créer un nouvel utilisateur.

b. Limiter le Nombre de Demandes

Pour éviter les abus, limitez le nombre de demandes de vérification par utilisateur ou par numéro de téléphone.

# models.py

import random
import string
from django.utils import timezone
from datetime import timedelta

class PhoneVerification(models.Model):
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='phone_verifications')
    code = models.CharField(max_length=6)
    created_at = models.DateTimeField(auto_now_add=True)
    is_verified = models.BooleanField(default=False)

    def is_expired(self):
        return self.created_at < timezone.now() - timedelta(minutes=10)  # Expire après 10 minutes

    def __str__(self):
        return f"Vérification de {self.user.email} - {'Validé' if self.is_verified else 'En attente'}"
Copier après la connexion
Copier après la connexion

c. Gestion des Utilisateurs lors de la Vérification

Vous pouvez décider de créer un utilisateur après la vérification ou associer le numéro à un utilisateur existant.

9. Tests et Validation

Assurez-vous de tester votre système en environnement de développement avant de le déployer en production. Vérifiez que :

  • Les SMS sont correctement envoyés.
  • Les codes sont générés et stockés de manière sécurisée.
  • Les vérifications expirent après le délai défini.
  • Les erreurs sont correctement gérées et communiquées à l'utilisateur.

Exemple Complet de Implémentation

Pour vous donner une vue d'ensemble, voici un exemple complet des fichiers concernés.

models.py

# settings.py

TWILIO_ACCOUNT_SID = 'votre_account_sid'
TWILIO_AUTH_TOKEN = 'votre_auth_token'
TWILIO_FROM_NUMBER = '+1234567890'  # Numéro Twilio
Copier après la connexion
Copier après la connexion

serializers.py

# utils.py

from django.conf import settings
from twilio.rest import Client

def send_sms(to, message):
    client = Client(settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN)
    message = client.messages.create(
        body=message,
        from_=settings.TWILIO_FROM_NUMBER,
        to=str(to)
    )
    return message.sid
Copier après la connexion
Copier après la connexion

views.py

# serializers.py

from rest_framework import serializers
from .models import CustomUser, PhoneVerification
from phonenumber_field.serializerfields import PhoneNumberField

class PhoneVerificationRequestSerializer(serializers.Serializer):
    phone_number = PhoneNumberField()

    def validate_phone_number(self, value):
        if CustomUser.objects.filter(phone_number=value).exists():
            raise serializers.ValidationError("Ce numéro de téléphone est déjà utilisé.")
        return value

class PhoneVerificationCodeSerializer(serializers.Serializer):
    phone_number = PhoneNumberField()
    code = serializers.CharField(max_length=6)

    def validate(self, data):
        phone_number = data.get('phone_number')
        code = data.get('code')

        try:
            user = CustomUser.objects.get(phone_number=phone_number)
        except CustomUser.DoesNotExist:
            raise serializers.ValidationError("Utilisateur non trouvé avec ce numéro de téléphone.")

        try:
            verification = PhoneVerification.objects.filter(user=user, code=code, is_verified=False).latest('created_at')
        except PhoneVerification.DoesNotExist:
            raise serializers.ValidationError("Code de vérification invalide.")

        if verification.is_expired():
            raise serializers.ValidationError("Le code de vérification a expiré.")

        data['user'] = user
        data['verification'] = verification
        return data
Copier après la connexion

urls.py

# views.py

from rest_framework import generics, status
from rest_framework.response import Response
from .serializers import PhoneVerificationRequestSerializer, PhoneVerificationCodeSerializer
from .models import CustomUser, PhoneVerification
from .utils import send_sms
import random
import string
from django.utils import timezone
from rest_framework.permissions import AllowAny

class PhoneVerificationRequestView(generics.GenericAPIView):
    serializer_class = PhoneVerificationRequestSerializer
    permission_classes = [AllowAny]

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        phone_number = serializer.validated_data['phone_number']

        # Générer un code de 6 chiffres
        code = ''.join(random.choices(string.digits, k=6))

        try:
            user = CustomUser.objects.get(phone_number=phone_number)
            # Si l'utilisateur existe déjà, ne pas permettre la création d'un nouveau
            return Response({"detail": "Ce numéro de téléphone est déjà associé à un utilisateur."}, status=status.HTTP_400_BAD_REQUEST)
        except CustomUser.DoesNotExist:
            pass  # Permettre la création si nécessaire

        # Créer une instance de PhoneVerification
        verification = PhoneVerification.objects.create(user=None, code=code)  # user=None pour l'instant

        # Envoyer le code par SMS
        try:
            send_sms(phone_number, f"Votre code de vérification est : {code}")
        except Exception as e:
            return Response({"detail": "Erreur lors de l'envoi du SMS."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        return Response({"detail": "Code de vérification envoyé."}, status=status.HTTP_200_OK)

class PhoneVerificationCodeView(generics.GenericAPIView):
    serializer_class = PhoneVerificationCodeSerializer
    permission_classes = [AllowAny]

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        verification = serializer.validated_data['verification']

        # Marquer la vérification comme validée
        verification.is_verified = True
        verification.save()

        # Mettre à jour l'utilisateur
        user.is_phone_verified = True
        user.save()

        return Response({"detail": "Numéro de téléphone vérifié avec succès."}, status=status.HTTP_200_OK)
Copier après la connexion

utils.py

# urls.py

from django.urls import path
from .views import PhoneVerificationRequestView, PhoneVerificationCodeView

urlpatterns = [
    path('api/verify-phone/request/', PhoneVerificationRequestView.as_view(), name='phone-verification-request'),
    path('api/verify-phone/verify/', PhoneVerificationCodeView.as_view(), name='phone-verification-verify'),
]
Copier après la connexion

10. Sécuriser et Optimiser

  • Limiter les Tentatives de Vérification : Implémentez un système pour limiter le nombre de tentatives de vérification afin d'éviter les attaques par force brute.

  • Chiffrer les Codes : Pour plus de sécurité, vous pouvez chiffrer les codes de vérification dans la base de données.

  • Utiliser des Tâches Asynchrones : Pour améliorer les performances, utilisez des tâches asynchrones (par exemple avec Celery) pour envoyer les SMS sans bloquer les requêtes API.

  • Configurer HTTPS : Assurez-vous que votre API est accessible via HTTPS pour sécuriser les communications.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal