Использование электронной почты вместо логина в django - PullRequest
7 голосов
/ 18 февраля 2010

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

Я хочу использовать электронные письма в качестве имен пользователей в данном проекте django. Однако я не могу повторно использовать поля, предоставленные моделью auth.User, по крайней мере по двум причинам:

  1. поле auth.User.username max_length составляет 30 символов, что может быть недостаточно для некоторых адресов электронной почты.

  2. auth.User.email не является уникальным, что явно не является достаточным условием для утверждения, что имена пользователей должны быть уникальными.

Таким образом, очевидным способом здесь является сохранение имени пользователя в пользовательском профиле, который связан с auth.User. В этом случае нам приходится сталкиваться со следующими проблемами:

  1. Создать уникальное имя пользователя для auth.User.username - здесь должен быть в порядке хэш электронной почты md5?
  2. Оставьте полностью auth.User.email пустым - поскольку его длина составляет всего 75 символов, а в соответствии с RFC 5321 ( Какова максимальная длина действительного адреса электронной почты? ), электронная почта может быть длинной до 256 символов.

Следующие проблемы вытекают из предложенного решения:

  1. Никто не сможет повторно использовать встроенные представления / шаблоны для стандартных операций, таких как сброс пароля и т. Д.
  2. В случае изменения адреса электронной почты auth.User.username необходимо будет обновить

Чтобы добавить масла в огонь, разработчики django вряд ли исправят это ограничение в обозримом будущем - см. http://code.djangoproject.com/ticket/11365

Таким образом, вопрос заключается в следующем: есть ли другой способ сделать это, и видите ли вы другие недостатки в предложенном выше решении?

Спасибо!

Ответы [ 7 ]

5 голосов
/ 18 февраля 2010

У меня был клиент с коммерческим сайтом, который работал с 1995 года (да, мы говорим здесь с ранними последователями). В любом случае, у них уже была установленная база пользователей, и имена были полностью несовместимыми с идеей Django о имени пользователя.

Я посмотрел на несколько способов справиться с этим, и все они были похожи на хаки (это было летом 2007 года), поэтому я сказал, что привинтил его и взломал contrib.auth.models.User напрямую. Мне нужно было всего лишь изменить около 10 строк кода, увеличить размер поля и настроить валидатор. С тех пор мы сделали два обновления - 0.97-pre => 1.0 и 1.0 => 1.1.1 - и каждый раз для «переноса хака» требуется всего около 15 минут.

Это не красиво, и я могу сгореть в аду за то, что сделал это таким образом, но потребовалось меньше времени, чтобы сделать это таким образом, чем все остальное, что я мог выяснить, и форвардные порты были абсолютно не проблема

2 голосов
/ 18 февраля 2010

Возможно, вы захотите взглянуть на то, как Satchmo решает эту проблему:

http://bitbucket.org/chris1610/satchmo/src/tip/satchmo/apps/satchmo_store/accounts/email-auth.py

и

http://bitbucket.org/chris1610/satchmo/src/533a63f955f8/satchmo/apps/satchmo_utils/unique_id.py

1 голос
/ 28 марта 2011

Я написал объяснение своего решения этой же проблемы: Аутентификация Django с использованием адреса электронной почты . В основном состоит из:

  • Создайте пользовательский сервер авторизации для аутентификации электронной почты.
  • Подкласс формы создания пользователя для добавления адреса электронной почты в качестве обязательного поля.
  • Скрыть поле имени пользователя от пользователя в формах создания и входа в систему.
  • Произвольно генерирует имя пользователя в представлении, которое обрабатывает форму создания.
  • Вручную добавить уникальный индекс в столбец электронной почты (Тьфу!)

Мое решение по-прежнему имеет 2 проблемы. Во-первых, ручное создание индекса базы данных не очень хорошо. Во-вторых, адрес электронной почты по-прежнему ограничен 75 символами (у меня не было проблем с портированием системы с примерно 8000 пользователей). Но он прекрасно работает с остальными приложениями Django и сторонних разработчиков.

0 голосов
/ 14 января 2019

для обеих аутентификаций [имя пользователя, адрес электронной почты] без изменения модели просто добавьте Backend:

метод и аутентификация [электронная почта, имя пользователя]

0 голосов
/ 04 декабря 2014

Я написал решение, основанное на ответе Доминика, которое включает в себя улучшения безопасности и некоторые дополнительные функции, такие как аутентификация с учетом регистра. Если вы предпочитаете, вы можете установить его прямо из pypi :

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.conf import settings

###################################
"""  DEFAULT SETTINGS + ALIAS   """
###################################


try:
    am = settings.AUTHENTICATION_METHOD
except:
    am = 'both'
try:
    cs = settings.AUTHENTICATION_CASE_SENSITIVE
except:
    cs = 'both'

#####################
"""   EXCEPTIONS  """
#####################


VALID_AM = ['username', 'email', 'both']
VALID_CS = ['username', 'email', 'both', 'none']

if (am not in VALID_AM):
    raise Exception("Invalid value for AUTHENTICATION_METHOD in project "
                    "settings. Use 'username','email', or 'both'.")

if (cs not in VALID_CS):
    raise Exception("Invalid value for AUTHENTICATION_CASE_SENSITIVE in project "
                    "settings. Use 'username','email', 'both' or 'none'.")

############################
"""  OVERRIDDEN METHODS  """
############################


class DualAuthentication(ModelBackend):
    """
    This is a ModelBacked that allows authentication
    with either a username or an email address.
    """

    def authenticate(self, username=None, password=None):
        UserModel = get_user_model()
        try:
            if ((am == 'email') or (am == 'both')):
                if ((cs == 'email') or cs == 'both'):
                    kwargs = {'email': username}
                else:
                    kwargs = {'email__iexact': username}

                user = UserModel.objects.get(**kwargs)
            else:
                raise
        except:
            if ((am == 'username') or (am == 'both')):
                if ((cs == 'username') or cs == 'both'):
                    kwargs = {'username': username}
                else:
                kwargs = {'username__iexact': username}

                user = UserModel.objects.get(**kwargs)
        finally:
            try:
                if user.check_password(password):
                    return user
            except:
                # Run the default password hasher once to reduce the timing
                # difference between an existing and a non-existing user.
                UserModel().set_password(password)
                return None

    def get_user(self, username):
        UserModel = get_user_model()
        try:
            return UserModel.objects.get(pk=username)
        except UserModel.DoesNotExist:
            return None
0 голосов
/ 28 марта 2011

Я просто использую этот djangosnippet , и пользователи могут использовать свое имя пользователя или адрес электронной почты.
Но это не решит ограничение в 75 символов, просто удобный фрагмент.

0 голосов
/ 18 февраля 2010

Я тоже должен признаться, что сгорю в аду. Недавно я развернул небольшое приложение, в котором разбил электронную почту пользователя, разделил ее на 30 символов и установил в качестве имени пользователя. Я подумал черт, каковы шансы? и прошел через это. Взял несколько строк кода и вуаля.

Я думаю, что ограничение на 75 символов было установлено как таковое, потому что люди обычно не имеют личных электронных писем так долго. Это просто вопрос сохранения пространства, потому что все эти неиспользуемые байты будут зарезервированы в любом случае (то есть значения NULL и более короткие / меньшие значения не являются свободными).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...