Использование нескольких полей входа, электронной почты или номера телефона в Django All Auth

#django #django-allauth #django-custom-user

#django #django-allauth #django-пользовательский пользователь

Вопрос:

Я использую Django All Auth для аутентификации пользователя, но мне нужно использовать номер телефона или поле электронной почты при входе в систему пользователя. Я расширил класс пользователя следующим образом:

 class User(AbstractUser):
    phone_number = models.CharField(max_length=10, unique=True)


    def __unicode__(self):
        return self.username 
  

Моя форма регистрации выглядит следующим образом:

 class SignupForm(forms.Form):
    phone_number = forms.CharField(max_length=10,label='phone_number')

    def signup(self, request, user):
        user.phone_number = self.cleaned_data['phone_number']
        user.save()
  

Номер телефона сохраняется в серверной части с помощью этого, но мне нужно аутентифицировать пользователя, если он вводит либо адрес электронной почты, либо номер телефона. Какой класс мне нужно расширить для Django All Auth. Я прочитал много вопросов, но не смог найти ничего хорошего.

Если я помещу ACCOUNT_USER_MODEL_USERNAME_FIELD = ‘phone_number’ в settings.py , он аутентифицируется по телефону, но не по электронной почте.

РЕДАКТИРОВАТЬ 1:

Я создал файл backends.py и я написал этот код

 class PhoneNumberBackend(object):
    """
    Custom Phone Number Backend to perform authentication via phone number
    """
    def authenticate(self, username=None, password=None):
        my_user_model = get_user_model()

        try:
            user = my_user_model.objects.get(phone_number=username)
            if user.check_password(password):
                return user # return user on valid credentials
        except my_user_model.DoesNotExist:
            return None # return None if custom user model does not exist 
        except:
            return None # return None in case of other exceptions

    def get_user(self, user_id):
        my_user_model = get_user_model()
        try:
            return my_user_model.objects.get(pk=user_id)
        except my_user_model.DoesNotExist:
            return None
  

Settings.py сейчас выглядит примерно так:

 AUTHENTICATION_BACKENDS = (
    # 'userauth.backends.PhoneNumberBackend',
    # Needed to login by username in Django admin, regardless of `allauth`
    'django.contrib.auth.backends.ModelBackend',

    # `allauth` specific authentication methods, such as login by e-mail
    'allauth.account.auth_backends.AuthenticationBackend',

)
  

Он должен проходить аутентификацию с использованием номера телефона, а если нет, то перейти к другим методам аутентификации, верно? Это так не работает.

Комментарии:

1. Я делал нечто подобное еще в прошлом. Я думаю, вам следует создать подкласс BaseUserManager class и определить свой собственный пользовательский менеджер с помощью нескольких настроек.

2. Но django all auth settings ACCOUNT_AUTHENTICATION_METHOD все равно будет применяться, даже если мы используем BaseUserManager. Нет?

Ответ №1:

сначала вам нужно создать сервер аутентификации в djagno, подобный этому, для электронной почты

 class EmailAuthentication(object):
def authenticate(self, request, username=None, password=None):
    try:
        user = User.objects.get(email=username)
        if user.check_password(password):
            return user
        return None
    except:
        return None
def get_user(self, user_id):
    try:
        return User.objects.get(id=user_id)
    except:
return None
  

вы можете создать еще одно поле для номера телефона
, но убедитесь, что они уникальны в вашей базе данных, чтобы никому не приходилось использовать учетные записи с одинаковыми учетными
данными, и вы можете проверить это в методе очистки формы, как это
снова это для электронной почты

 def clean_email(self):
    email = self.cleaned_data['email']
    if User.objects.filter(email=email).exists():
        raise forms.ValidationError(' user with this email is already registered -- Try loginigin or resting the password')    
    return email
  

затем вы должны поместить серверную часть аутентификации в файл настроек и не забудьте включить исходную серверную часть имени пользователя django

 AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'account.authentication.EmailAuthentication',
]
  

в предыдущем коде я предположил, что ваш сервер аутентификации находится внутри файла с именем authentication в приложении account

затем в представлении вы аутентифицируете пользователя, а затем регистрируете его

   username = form.cleaned_data['username']
  password = form.cleaned_data['password2']
  user = authenticate(username=username, password=password)
  if user:
      login(request, user)
  

или вы можете использовать LoginView из django.contrib.auth.views, чтобы упростить задачу

Комментарии:

1. Поскольку я использую Django All Auth, у него уже есть AuthenticationBackend, который мы должны каким-то образом расширить, чтобы разрешить номер телефона или любое другое поле в качестве логина. Я создал еще один серверный сервер только для телефона, но все еще не понимаю, правильно это или нет

2. таким образом, вы расширяете его, чтобы успокоить себя, этот способ взят из книги примеров django2by, и я использовал его с небольшими изменениями

3. когда вы устанавливаете серверные части аутентификации в настройках, django пытается аутентифицировать пользователя с каждым из них подряд, и если он найдет один auth, который знает пользователя, он остановится

4. я не вижу необходимости делать два исключения, если то же самое вернет тот же результат, если вы хотите, вы можете поделиться кодом на github, чтобы я мог отредактировать его или просмотреть полный цикл аутентификации, я не эксперт, чтобы давать правильные предположения

5. Этого еще нет в git. Что я могу сказать, так это то, что используемый вид входа является представлением allauth по умолчанию или вы думаете, что мне нужно его переопределить?