MongoEngine - как настраивать пользовательскую модель/пользовательский бэкэнд для аутентификации()

СУЩНОСТЬ

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

Есть ли какая-либо документация с прямолинейным (и полным!) примером использования пользовательского объекта пользователя при использовании Mongo в качестве основного хранилища данных при аутентификации в Django? (Postgres имеет такие четкие и более всеобъемлющие документы...)


ДЕТАЛЬ

MongoEngine, по-видимому, дает вам только два варианта аутентификации - "Классический" (например, "mongoengine.django.auth.MongoEngineBackend" )... ИЛИ... "Пользовательская модель пользователя" (также известный как "django. contrib.auth.backends.ModelBackend ') - оба из которых более или менее кратко изложены в Николасе Кортоте, отвечая на другой вопрос здесь:

Python-Social-Auth не работает с mongoEngine (Django)

Оба этих метода аутентификации дают вам доступ к методу authenticate(), аналогичному классу Django AbstractBaseUser, - методу, который полагается на функцию check_password. Тем не менее, в тот момент, когда вы используете так называемую "пользовательскую модель пользователя", аутентификацию (как указано в приведенной выше ссылке)... и затем соединяйте ее с пользовательским бэкэнд (для использования электронных писем для имен пользователей)... вы возникают проблемы из-за отсутствия доступа к типичной функции authenticate().

Например, так...

accounts.models.py


# ...with postgres, I'd subclass AbstractBaseUser...but with Mongo...(?)

from django.conf import settings
from mongoengine.fields import EmailField, BooleanField 
from mongoengine.django.auth import User class MyUser(User): email = EmailField(max_length=254, unique=True) is_active = BooleanField(default=True) is_admin = BooleanField(default=False) USERNAME_FIELD = 'email' REQUIRED_FIELDS = '' ...


my_custom_backend.py

# ...is a custom backend even necessary to use email for authentication instead of username?

from django.conf import settings
from django.contrib.auth.models import check_password
#from mongoengine.django.auth import check_password
#from django.contrib.auth.hashers import check_password
from models import MyUser

    class EmailAuthBackend(object):

        def authenticate(self, email=None, password=None):

# ...uh oh, since I'm NOT using one of the usual backends with a pre-existing authenticate()
# method, there ain't a native check_password() function available. Means I have to hash the
# password, etc.

Итак, похоже, я обязан написать свою собственную функцию check_password. Чтобы получить всю доброту, присущую классу AbstractBaseUser, обычно найденному с помощью проверки PostgreSQL, мне пришлось бы полностью раздуть мою пользовательскую модель пользователя, которая кажется взломанной и не может быть очень СУХОЙ.

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

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

Потому что - как это сейчас - я получаю объект 'AnonymousUser', в браузере отсутствует сообщение об ошибке "backend" . Я также отметил, что эта проблема иногда возникает по непредвиденным причинам, а именно: возможно, метод authenticate() ожидает хешированный пароль или потому, что логин (электронная почта) слишком длинный...? Для большего количества случаев, когда это последнее обстоятельство может иметь место, см.:

Объект регистрации Django 'AnonymousUser' не имеет атрибута 'backend'


settings.py

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.admin',
    'mongoengine.django.mongo_auth',
    'accounts',
)

AUTHENTICATION_BACKENDS = (
    'mongoengine.django.auth.MongoEngineBackend',
    #'accounts.my_custom_backend.EmailAuthBackend',
    #'django.contrib.auth.backends.ModelBackend',
)

AUTH_USER_MODEL = 'mongo_auth.MongoUser'
MONGOENGINE_USER_DOCUMENT = 'accounts.models.User'


accounts.views.py

from django.contrib.auth import login as django_login
from my_custom_backend import EmailAuthBackend
from forms import AuthenticationForm

def login(request):

    form = AuthenticationForm(data=request.POST)
    if form.is_valid():
        try:
            backend = EmailAuthBackend()
            user = backend.authenticate(email=request.POST['email'], password=request.POST['password'])
            django_login(request, user)
            return redirect('/')
        except DoesNotExist:
            return HttpResponse('user does not exist')
    else:
        form = AuthenticationForm()

    return render_to_response('accounts/login.html',
       { 'form': form },
       context_instance=RequestContext(request))

Ответ 1

Ну, похоже, лучший способ действий - не сдавать Django User to Mongo для аутентификации для начала... Получил этот золотой самородок через Twitter:

@blogblimp мой короткий ответ: старайтесь избегать замены пользовательских моделей Django на MongoDB. Вы теряете всю мощь Django и теряете скорость MongoDB. Серьезно, пользователь относится ко всему, и MongoDB не является реляционным.

— Дэниел Рой Гринфельд (@pydanny) 20 января 2014 г.


Итак: я просто использую PostgreSQL для аутентификации, а Mongo - для других объектов. Это означает, что имена/подключения к двум базам данных в настройках Django. Оглядываясь назад, я думаю, что мораль: никогда не используйте Монго только потому, что он крут. Монго по-прежнему является гражданином второго сорта в мире Джанго.

Ответ 2

Возможно, я немного опаздываю, но я мог бы выполнить задачу аутентификации по электронной почте, используя mongoengine User + django authenticate, вот как я работаю:

from django.contrib.auth import authenticate, login as do_login, logout as do_logout

def login(request):

    data = extractDataFromPost(request)
    email = data["email"]
    password = data["password"]

    try: 
        user = User.objects.get(username=email)
        if user.check_password(password):
            user.backend = 'mongoengine.django.auth.MongoEngineBackend'
            user = authenticate(username=email, password=password)
            do_login(request, user)
            request.session.set_expiry(3600000) # 1 hour timeout
            return jsonResponse(serializeUser(user)) 
        else:
            result = {'error':True, 'message':'Invalid credentials'}
            return jsonResponse(result) 
    except User.DoesNotExist:
        result = {'error':True, 'message':'Invalid credentials'}
        return jsonResponse(result)