>백엔드 개발 >파이썬 튜토리얼 >drf 프로젝트에서 전화번호 확인 구현

drf 프로젝트에서 전화번호 확인 구현

Mary-Kate Olsen
Mary-Kate Olsen원래의
2024-12-28 10:17:10194검색

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

Django REST Framework(DRF)로 전화번호 인증 시스템을 구현하려면 다음 단계를 따르세요. 이 시스템을 통해 사용자는 전화번호를 제공하고, SMS(예: Twilio를 통해)로 확인 코드를 받고, 이 코드를 확인하여 번호를 확인할 수 있습니다.

주요 단계:

  1. 필요한 종속성 설치
  2. 전화번호를 포함하도록 사용자 템플릿 편집
  3. 인증 코드를 저장할 템플릿 만들기
  4. SMS 전송 서비스 구성(예: Twilio)
  5. DRF 시리얼라이저 생성
  6. 뷰 및 API 경로 생성
  7. 검증 로직 및 보안 관리

1. 필요한 종속성 설치

먼저 필요한 라이브러리를 설치했는지 확인하세요.

  • Django REST 프레임워크: 아직 하지 않으셨다면
  • Twilio: SMS 전송용.
  • django-phonenumber-field: 전화번호를 확인하고 형식을 지정합니다.

pip를 통해 설치:

pip install djangorestframework twilio django-phonenumber-field

settings.py의 INSTALLED_APPS에 Phonenumber_field 및 Rest_framework를 추가하세요.

# settings.py

INSTALLED_APPS = [
    # ...
    'rest_framework',
    'phonenumber_field',
    # ...
]

2. 전화번호를 포함하도록 사용자 템플릿을 변경합니다.

맞춤 사용자 템플릿을 사용하는 경우 전화번호 및 확인 플래그 필드를 추가하세요.

# 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

참고: 이미 사용자 모델이 있는 경우에는 Phone_number 및 is_phone_verified 필드를 적절하게 추가해야 합니다.

3. 인증 코드를 저장할 템플릿 만들기

이 템플릿은 사용자에게 전송된 인증 코드를 저장합니다.

# 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'}"

4. SMS 전송 서비스 구성(예: Twilio)

Twilio를 사용하여 문자 메시지를 보낼 수 있습니다. 먼저 Twilio 계정을 만들고 필요한 자격 증명(ACCOUNT_SID, AUTH_TOKEN, FROM_NUMBER)을 획득하세요.

settings.py에 다음 구성을 추가하세요.

# settings.py

TWILIO_ACCOUNT_SID = 'votre_account_sid'
TWILIO_AUTH_TOKEN = 'votre_auth_token'
TWILIO_FROM_NUMBER = '+1234567890'  # Numéro Twilio

SMS 전송을 관리하기 위한 utils.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

5. DRF 직렬 변환기 생성

확인 요청 및 코드 유효성 검사를 처리하기 위한 직렬 변환기를 만듭니다.

pip install djangorestframework twilio django-phonenumber-field

6. API 보기 및 경로 생성

확인 요청 및 코드 유효성 검사를 관리하기 위한 뷰를 만듭니다.

# settings.py

INSTALLED_APPS = [
    # ...
    'rest_framework',
    'phonenumber_field',
    # ...
]

참고: 확인 중에 사용자를 생성하거나 기존 사용자를 다르게 관리하려는 경우 등 필요에 따라 이러한 보기를 조정할 수 있습니다.

7. API 경로 구성

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

8. 추가 로직 추가(선택 사항)

가지다. 사용자별 고유 코드 생성

요청 보기를 편집하여 코드를 특정 사용자와 연결하거나 새 사용자를 생성하세요.

비. 요청 수 제한

악용을 방지하려면 사용자 또는 전화번호당 인증 요청 수를 제한하세요.

# 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'}"

기음. 검증 중 사용자 관리

인증 후 사용자를 생성하거나 해당 번호를 기존 사용자와 연결할 수 있습니다.

9. 테스트 및 검증

시스템을 프로덕션 환경에 배포하기 전에 개발 환경에서 테스트해 보시기 바랍니다. 다음 사항을 확인하세요.

  • SMS 메시지가 올바르게 전송되었습니다.
  • 코드가 생성되어 안전하게 저장됩니다.
  • 설정된 시간이 지나면 수표가 만료됩니다.
  • 오류가 올바르게 처리되고 사용자에게 전달됩니다.

완전한 구현 예

개요를 설명하기 위해 영향을 받는 파일의 전체 예는 다음과 같습니다.

models.py

# settings.py

TWILIO_ACCOUNT_SID = 'votre_account_sid'
TWILIO_AUTH_TOKEN = 'votre_auth_token'
TWILIO_FROM_NUMBER = '+1234567890'  # Numéro Twilio

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

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

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)

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'),
]

10. 보안 및 최적화

  • 확인 시도 제한: 무차별 대입 공격을 방지하기 위해 확인 시도 횟수를 제한하는 시스템을 구현합니다.

  • 코드 암호화: 보안 강화를 위해 데이터베이스의 확인 코드를 암호화할 수 있습니다.

  • 비동기 작업 사용: 성능을 향상하려면 비동기 작업(예: Celery 사용)을 사용하여 API 요청을 차단하지 않고 SMS를 보내세요.

  • HTTPS 구성: 보안 통신을 위해 HTTPS를 통해 API에 액세스할 수 있는지 확인하세요.

위 내용은 drf 프로젝트에서 전화번호 확인 구현의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.