Rumah > pembangunan bahagian belakang > Tutorial Python > Melaksanakan pengesahan nombor telefon dalam projek drf

Melaksanakan pengesahan nombor telefon dalam projek drf

Mary-Kate Olsen
Lepaskan: 2024-12-28 10:17:10
asal
135 orang telah melayarinya

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

Untuk melaksanakan sistem pengesahan nombor telefon dengan Django REST Framework (DRF), anda boleh mengikuti langkah berikut. Sistem ini akan membenarkan pengguna memberikan nombor telefon mereka, menerima kod pengesahan melalui SMS (contohnya melalui Twilio) dan mengesahkan kod ini untuk mengesahkan nombor mereka.

Langkah Utama:

  1. Pasang kebergantungan yang diperlukan
  2. Edit templat pengguna untuk memasukkan nombor telefon
  3. Buat templat untuk menyimpan kod pengesahan
  4. Konfigurasikan perkhidmatan penghantaran SMS (cth. Twilio)
  5. Buat penyeri DRF
  6. Buat paparan dan laluan API
  7. Urus logik dan keselamatan pengesahan

1. Pasang Ketergantungan yang Diperlukan

Pertama, pastikan anda telah memasang perpustakaan yang diperlukan:

  • Rangka Kerja Django REST: Jika anda belum melakukannya.
  • Twilio: Untuk menghantar SMS.
  • django-phonenumber-field: Untuk mengesahkan dan memformat nombor telefon.

Pasangnya melalui pip:

pip install djangorestframework twilio django-phonenumber-field
Salin selepas log masuk
Salin selepas log masuk

Tambah phonenumber_field dan rest_framework pada INSTALLED_APPS anda dalam tetapan.py:

# settings.py

INSTALLED_APPS = [
    # ...
    'rest_framework',
    'phonenumber_field',
    # ...
]
Salin selepas log masuk
Salin selepas log masuk

2. Tukar Templat Pengguna kepada Sertakan Nombor Telefon

Jika anda menggunakan templat pengguna tersuai, tambahkan medan untuk nombor telefon dan bendera pengesahan.

# 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
Salin selepas log masuk
Salin selepas log masuk

Nota: Jika anda sudah mempunyai model pengguna, pastikan anda menambah medan phone_number dan is_phone_verified dengan sewajarnya.

3. Cipta Templat untuk Menyimpan Kod Pengesahan

Templat ini akan menyimpan kod pengesahan yang dihantar kepada pengguna.

# 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'}"
Salin selepas log masuk
Salin selepas log masuk

4. Konfigurasikan Perkhidmatan Menghantar SMS (Cth. Twilio)

Anda boleh menggunakan Twilio untuk menghantar mesej teks. Mulakan dengan membuat akaun Twilio dan dapatkan bukti kelayakan yang diperlukan (ACCOUNT_SID, AUTH_TOKEN, FROM_NUMBER).

Tambahkan konfigurasi ini pada tetapan anda.py:

# settings.py

TWILIO_ACCOUNT_SID = 'votre_account_sid'
TWILIO_AUTH_TOKEN = 'votre_auth_token'
TWILIO_FROM_NUMBER = '+1234567890'  # Numéro Twilio
Salin selepas log masuk
Salin selepas log masuk

Buat fail utils.py untuk mengurus penghantaran 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
Salin selepas log masuk
Salin selepas log masuk

5. Cipta DRF Serializers

Buat penyeri bersiri untuk mengendalikan permintaan pengesahan dan pengesahan kod.

pip install djangorestframework twilio django-phonenumber-field
Salin selepas log masuk
Salin selepas log masuk

6. Cipta Paparan dan Laluan API

Buat paparan untuk mengurus permintaan pengesahan dan pengesahan kod.

# settings.py

INSTALLED_APPS = [
    # ...
    'rest_framework',
    'phonenumber_field',
    # ...
]
Salin selepas log masuk
Salin selepas log masuk

Nota: Anda mungkin mahu melaraskan paparan ini mengikut keperluan, seperti jika anda ingin mencipta pengguna semasa pengesahan atau mengurus pengguna sedia ada secara berbeza.

7. Konfigurasi Laluan API

Tambahkan laluan yang sepadan dalam urls.py anda.

# 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
Salin selepas log masuk
Salin selepas log masuk

8. Tambah Logik Tambahan (Pilihan)

mempunyai. Penjanaan Kod Unik bagi setiap Pengguna

Edit paparan permintaan untuk mengaitkan kod dengan pengguna tertentu atau buat pengguna baharu.

b. Hadkan Bilangan Permintaan

Untuk mengelakkan penyalahgunaan, hadkan bilangan permintaan pengesahan bagi setiap pengguna atau nombor telefon.

# 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'}"
Salin selepas log masuk
Salin selepas log masuk

c. Pengurusan Pengguna semasa Pengesahan

Anda boleh memutuskan untuk membuat pengguna selepas pengesahan atau mengaitkan nombor tersebut dengan pengguna sedia ada.

9. Ujian dan Pengesahan

Pastikan anda menguji sistem anda dalam persekitaran pembangunan sebelum menggunakannya untuk pengeluaran. Semak bahawa:

  • Mesej SMS dihantar dengan betul.
  • Kod dijana dan disimpan dengan selamat.
  • Cek tamat tempoh selepas masa yang ditetapkan.
  • Ralat dikendalikan dengan betul dan disampaikan kepada pengguna.

Contoh Perlaksanaan Lengkap

Untuk memberi anda gambaran keseluruhan, berikut ialah contoh lengkap fail yang terjejas.

models.py

# settings.py

TWILIO_ACCOUNT_SID = 'votre_account_sid'
TWILIO_AUTH_TOKEN = 'votre_auth_token'
TWILIO_FROM_NUMBER = '+1234567890'  # Numéro Twilio
Salin selepas log masuk
Salin selepas log masuk

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
Salin selepas log masuk
Salin selepas log masuk

pandangan.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
Salin selepas log masuk

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)
Salin selepas log masuk

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'),
]
Salin selepas log masuk

10. Selamat dan Optimumkan

  • Hadkan Percubaan Pengesahan: Laksanakan sistem untuk mengehadkan bilangan percubaan pengesahan untuk mengelakkan serangan kekerasan.

  • Sulitkan Kod: Untuk keselamatan tambahan, anda boleh menyulitkan kod pengesahan dalam pangkalan data.

  • Gunakan Tugas Asynchronous: Untuk meningkatkan prestasi, gunakan tugas tak segerak (contohnya dengan Celery) untuk menghantar SMS tanpa menyekat permintaan API.

  • Konfigurasikan HTTPS: Pastikan API anda boleh diakses melalui HTTPS untuk menjamin komunikasi.

Atas ialah kandungan terperinci Melaksanakan pengesahan nombor telefon dalam projek drf. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan