概要
如何使用Django + MongoEngine自定义用户模型和自定义身份验证后端(以允许电子邮件/密码身份验证)?(自定义后端是否为自定义后端必要的吗?...即,在使用MongoEngine进行身份验证时使用电子邮件作为用户名。)
在使用 Mongo 作为主数据存储区时,是否存在使用自定义用户对象的直接(且完整!)示例的文档em>在Django中验证?(Postgres有更清晰,更全面的文档...)
DETAIL
MongoEngine似乎只提供两种身份验证 - “经典”(又名“ mongoengine.django.auth.MongoEngineBackend ”)方式......或者......“自定义用户”模型“(又名' django.contrib.auth.backends.ModelBackend ')方式 - 这两种方式在Nicolas Cortot对这个问题的回答中或多或少简洁地概述了: /> Python-Social-Auth fails with mongoEngine (Django)
这两种身份验证技术都允许您访问类似于Django的AbstractBaseUser类的 authenticate()方法 - 一种依赖于 check_password 函数的方法。但是,您使用所谓的“自定义用户模型”身份验证风格(如上面链接中所述)...... 和然后将其与自定义后端配对(为了使用电子邮件)对于用户名)...由于无法访问典型的authenticate()函数而遇到麻烦。
例如,像这样......
# ...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 = '' ...
# ...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函数。为了获得通常在PostgreSQL身份验证中找到的 AbstractBaseUser 类所固有的所有优点,我必须完全膨胀我的自定义用户模型,这似乎是hacky并且不能非常干。
我在这里完全糊涂了吗? ...即,如果我想在使用MongoEngine时使用电子邮件而不是用户名进行身份验证,那么实际上完全没必要使用自定义后端吗?
我觉得我可能对Django在身份验证方面如何与MongoEngine一起工作有一个基本的误解,关于我如何在该过程中建模和调用自定义用户对象/我特定的MongoEngine用户对象的子类。 ..
因为 - 就像现在一样 - 我在浏览器中得到一个“'AnonymousUser'对象没有属性'backend'”错误消息。我还注意到这个问题有时会出于意料之外的原因 - 即:authenticate()方法可能需要散列密码,或者因为登录(电子邮件)太长了......?对于可能出现后一种情况的更多情况,请参阅:
Django Register Form 'AnonymousUser' object has no attribute 'backend'
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'
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))
答案 0 :(得分:5)
嗯,看起来最好的行动方案是不要将Django的用户移交给Mongo进行身份验证开始......通过Twitter获得这个金块:
@blogblimp我的简短回答:尽量避免用MongoDB替换Django用户模型。你失去了所有Django的力量并失去了MongoDB的速度。 说真的,用户与一切都有关,MongoDB不是关系型的。
- Daniel Roy Greenfeld(@pydanny)January 20, 2014
所以:我只是利用PostgreSQL进行身份验证,将Mongo用于其他对象。这意味着在Django设置中命名/连接到两个数据库。回想起来,我认为道德是:永远不要使用Mongo,因为它很酷。 Mongo仍然是Django世界的二等公民。
答案 1 :(得分: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)