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.
Pertama, pastikan anda telah memasang perpustakaan yang diperlukan:
Pasangnya melalui pip:
pip install djangorestframework twilio django-phonenumber-field
Tambah phonenumber_field dan rest_framework pada INSTALLED_APPS anda dalam tetapan.py:
# settings.py INSTALLED_APPS = [ # ... 'rest_framework', 'phonenumber_field', # ... ]
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
Nota: Jika anda sudah mempunyai model pengguna, pastikan anda menambah medan phone_number dan is_phone_verified dengan sewajarnya.
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'}"
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
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
Buat penyeri bersiri untuk mengendalikan permintaan pengesahan dan pengesahan kod.
pip install djangorestframework twilio django-phonenumber-field
Buat paparan untuk mengurus permintaan pengesahan dan pengesahan kod.
# settings.py INSTALLED_APPS = [ # ... 'rest_framework', 'phonenumber_field', # ... ]
Nota: Anda mungkin mahu melaraskan paparan ini mengikut keperluan, seperti jika anda ingin mencipta pengguna semasa pengesahan atau mengurus pengguna sedia ada secara berbeza.
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
Edit paparan permintaan untuk mengaitkan kod dengan pengguna tertentu atau buat pengguna baharu.
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'}"
Anda boleh memutuskan untuk membuat pengguna selepas pengesahan atau mengaitkan nombor tersebut dengan pengguna sedia ada.
Pastikan anda menguji sistem anda dalam persekitaran pembangunan sebelum menggunakannya untuk pengeluaran. Semak bahawa:
Untuk memberi anda gambaran keseluruhan, berikut ialah contoh lengkap fail yang terjejas.
# settings.py TWILIO_ACCOUNT_SID = 'votre_account_sid' TWILIO_AUTH_TOKEN = 'votre_auth_token' TWILIO_FROM_NUMBER = '+1234567890' # Numéro Twilio
# 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
# 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
# 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)
# 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'), ]
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!