Как лучше всего использовать номер телефона и код проверки в django?

Я хочу создать бэкенд аппликацию на django, и я хочу иметь аутотификацию используя только номер телефона, после того как клиент напишет номер телефона он получит код по смс, какой лучший способ решить эту задачу?

как изменить методы login и authaticate в базовой модели пользователя django

Чтобы реализовать аутентификацию по номеру телефона в Django, вы можете создать пользовательскую модель пользователя, которая наследует от AbstractUser следующим образом:

from django.db import models
from django.contrib.auth.models import AbstractUser
from .manager import UserManager

    class User(AbstractUser):
        phone_number = models.CharField(max_length=12, unique=True)
        USERNAME_FIELD = 'phone_number'
        REQUIRED_FIELDS = []
        objects = UserManager()

также вам нужно что-то вроде этого:

https://pypi.org/project/django-phone-verify/

https://github.com/CuriousLearner/django-phone-verify

и это geek for geeks тоже может помочь, но с небольшими обновлениями

https://www.geeksforgeeks.org/customizing-phone-number-authentication-in-django/

Если я правильно понял, вы хотите войти в систему, выполнив следующие действия:

  1. Пользователь вводит номер телефона
  2. Отправляется запрос на OTP
  3. Пользователь вводит OTP
  4. Если совпадает, аутентификация пользователя

Похоже, вам нужно написать пользовательскую модель пользователя и пользовательский бэкэнд аутентификации. Обратитесь к ним:

Что касается собственно OTP, то мне недавно пришлось его реализовать, поэтому я просто поделюсь тем, как я это сделал. Я сделал целое приложение, так как буду часто его использовать.

otp/models.py

def generate_otp5():
    random_generator = SystemRandom()
    return random_generator.randint(10000, 99999)

def generate_expiry_10m():
    now = datetime.now(tz=timezone.utc)
    ten_minutes = timedelta(minutes=10)
    return now + ten_minutes

class RegistrationOTP(BasePhoneNumberOTP):
    date_created = models.DateTimeField(auto_now_add=True)
    date_expired = models.DateTimeField(default=generate_expiry_10m)
    date_used = models.DateTimeField(blank=True, null=True)
    otp = models.IntegerField(default=generate_otp5)
    phone_number = PhoneNumberField()
    # from django-phonenumber-field
    
    @property
    def is_expired(self):
    now = datetime.now(tz=timezone.utc)
    return now >= self.date_expired

    @property
    def is_used(self):
        if self.date_used:
            return True
        return False

Затем я создал службу, потому что чувствовал, что она должна быть. Поместите его внутри вашего models.py, если хотите.

otp/services.py

class RegistrationOTPService:
    def __init__(self, phone_number: phonenumber, user_provided_otp: int):
        self.phone_number = phone_number
        self.user_provided_otp = user_provided_otp

    def resolve(self):
        # Used transaction in case multiple requests are made at the same time.
        with transaction.atomic():
            try:
                latest_record = (
                    RegistrationOTP.objects.select_for_update()
                    .filter(phone_number=self.phone_number)
                    .latest('date_created')
                )
            except exceptions.ObjectDoesNotExist as e:
                raise InvalidOTPError from e

            if latest_record.is_expired:
                raise InvalidOTPError

            if latest_record.is_used:
                raise InvalidOTPError

            if latest_record.otp != self.user_provided_otp:
                raise InvalidOTPError

            latest_record.date_used = datetime.now(tz=timezone.utc)
            latest_record.save()

Последнее, что я поместил в сериализатор validate(). В вашем случае это должно быть в бэкенде аутентификации.

    try:
        otp_service = RegistrationOTPService(
            phone_number=data.get('phone_number'),
            user_provided_otp=data.get('otp'),
        )
        otp_service.resolve()
    except InvalidOTPError as e:
        raise serializers.ValidationError({'otp': e}) from e
Вернуться на верх