如何自定义用户模型/用于authenticate()的自定义后端

概要

如何使用Django + MongoEngine自定义用户模型和自定义身份验证后端(以允许进行电子邮件/密码身份验证)? (是否需要自定义后端?即,在使用MongoEngine进行身份验证时使用电子邮件发送用户名)。

在使用Django进行身份验证时,是否有任何使用Mongo作为主数据存储的自定义用户对象的直接(且完整!)示例文档? (Postgres有更清晰和更全面的文档...)


详情

MongoEngine似乎给你两种风格的认证 - “经典”(又名'mongoengine.django.auth.MongoEngineBackend')方式...或者...“自定义用户模型”(又名'django.contrib.auth .backends.ModelBackend') - 在Nicolas Cortot对另一个问题的回答中,或多或少简洁地概述了这两种方法:

Python-Social-Auth与mongoEngine(Django)失败

这两种身份验证技术都允许您访问类似于Django的AbstractBaseUser类的authenticate()方法 - 一种依赖于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函数。 为了获得通常通过PostgreSQL身份验证获得的AbstractBaseUser类所固有的所有优点,我必须将我的自定义用户模型完全充满,这似乎很难做,并且不能很干。

我在这里完全困惑吗? ...即,如果我想在使用MongoEngine时使用电子邮件而不是用户名进行身份验证,那么实际上完全没有必要使用自定义后端?

我觉得我可能对Django在身份验证方面如何与MongoEngine一起工作存在根本的误解,并且关于我在该过程中如何建模并调用了自定义用户对象/ MongoEngine用户对象的特定子类...

因为 - 就像现在一样 - 我在浏览器中得到一个“ 'AnonymousUser''对象没有属性'backend' ”的错误信息。 我也注意到这个问题有时候会出于意想不到的原因 - 也就是说,authenticate()方法需要一个哈希密码,或者因为登录(email)太长了......? 有关后一种情况可能出现的更多情况,请参阅:

Django注册表单'AnonymousUser'对象没有属性'后端'


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))

那么,看起来最好的行动方式不是将Django的用户移交给Mongo,以便开始进行身份验证......通过Twitter获得了这个金块:

@blogblimp我的简短回答:尽量避免用MongoDB替换Django用户模型。 你失去了所有Django的力量,并失去了MongoDB的速度。 说真的,用户涉及到一切,而MongoDB不是关系型的。

- Daniel Roy Greenfeld(@pydanny)2014年1月20日


所以:我只会利用PostgreSQL进行身份验证,而Mongo则利用其他对象。 这意味着命名/连接到Django设置中的两个数据库。 回想起来,我想道德是:绝不使用Mongo,因为它很酷。 Mongo仍然是Django世界中的二等公民。


也许我有点晚了,但我可以使用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)
链接地址: http://www.djcxy.com/p/33799.html

上一篇: how to custom User model / custom backend for authenticate()

下一篇: Best Practice for following multiple authentication backends in Django?