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)