使用电子邮件和密码验证用户

时间:2013-05-18 15:03:37

标签: django

我的表单只允许用户通过用户名登录。我决定只允许用户通过电子邮件而不是用户名登录。

首先,这不是与通过电子邮件进行日志记录相关的任何问题的重复,因为在我的方案中,我在forms.py中验证并验证用户,然后再进入最终登录视图,这样就给了我机会为错误的登录密码等引发错误。

我面临的问题是我修改了我的forms.py以引发错误,如果电子邮件不存在有效,但它不会让用户通过他的电子邮件登录。

 def LoginRequest(request):
     form = LoginForm(request.POST or None)    
     if request.POST and form.is_valid():
         user = form.login(request)
         if user:
             login(request, user)
             return HttpResponseRedirect(reverse('Hello'))

     return render(request, 'login.html',{'form': form})

这是我的原始代码,只允许用户通过用户名

登录
 class LoginForm(forms.Form):
     username = forms.CharField()
     password = forms.CharField(
        widget=forms.PasswordInput(render_value=False)
        )

     def clean(self):        
         username = self.cleaned_data.get('username')
         password = self.cleaned_data.get('password')
         user = authenticate(username=username, password=password)
         if not user or not user.is_active:
             raise forms.ValidationError("Sorry, that login was invalid. Please try again.")
         return self.cleaned_data

     def login(self, request):
         username = self.cleaned_data.get('username')
         password = self.cleaned_data.get('password')
         user = authenticate(username=username, password=password)
         return user

这是我修改过的代码,只允许用户通过电子邮件登录。我想了很多我会怎么做但这是我提出的最好的主意。对不起,这有点令人困惑。 问题是,它不会让用户登录。我不明白为什么。

 class LoginForm(forms.Form):
     username = forms.CharField()
     password = forms.CharField(
            widget=forms.PasswordInput(render_value=False)
        )

     def clean(self):       
         user = self.cleaned_data.get('username')
         password = self.cleaned_data.get('password')

         if User.objects.filter(email=user).exists():
             password = self.cleaned_data.get('password')
             user = authenticate(username=user.username, password=password)
             if not user or not user.is_active:
                 raise forms.ValidationError("Sorry, that login was invalid. Please try again.")
             return self.cleaned_data

     def login(self, request):
         username = self.cleaned_data.get('username')
         password = self.cleaned_data.get('password')
         user = authenticate(username=username, password=password)
         return user

有人可以帮帮我吗?

3 个答案:

答案 0 :(得分:7)

由于dougis指出您正在尝试使用电子邮件对用户进行身份验证,但authenticate函数会根据用户名和密码对用户进行身份验证。所以这是使用电子邮件验证用户的技巧(完整的工作表单):

from django.db.models import Q
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.models import User
from django import forms
from django.contrib.auth import authenticate

class LoginForm(forms.Form):
    email = forms.CharField()
    password = forms.CharField(
        widget=forms.PasswordInput(render_value=False)
        )

    def clean(self):
        user = self.authenticate_via_email()
        if not user:
            raise forms.ValidationError("Sorry, that login was invalid. Please try again.")
        else:
            self.user = user
        return self.cleaned_data

    def authenticate_user(self):
        return authenticate(
            username=self.user.username,
            password=self.cleaned_data['password'])

    def authenticate_via_email(self):
        """
            Authenticate user using email.
            Returns user object if authenticated else None
        """
        email = self.cleaned_data['email']
        if email:
            try:
                user = User.objects.get(email__iexact=email)
                if user.check_password(self.cleaned_data['password']):
                    return user
            except ObjectDoesNotExist:
                pass
        return None

views.py

def LoginRequest(request):
    form = LoginForm(request.POST or None)    
    if request.method == 'POST' and form.is_valid():
        user = form.authenticate_user()
        login(request, user)
        return HttpResponseRedirect(reverse('Hello'))

    return render(request, 'login.html',{'form': form})

答案 1 :(得分:5)

您还可以编写自定义后端:

# yourapp.backends.py    
from django.contrib.auth.models import User


class EmailOrUsernameModelBackend(object):
    """ Authenticate user by username or email """
    def authenticate(self, username=None, password=None):
        if '@' in username:
            kwargs = {'email': username}
        else:
            kwargs = {'username': username}
        try:

            user = User.objects.get(**kwargs)
            if user.check_password(password):
                return user
            else:
                return None
        except User.DoesNotExist:
            return None

    def get_user(self, user_id=None):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

现在将后端添加到settings.py:

AUTHENTICATION_BACKENDS = (
    'yourapp.backends.EmailOrUsernameModelBackend',
    'django.contrib.auth.backends.ModelBackend',
)

答案 2 :(得分:1)

看起来您正在测试2个不同的字段。 您根据电子邮件查找用户

if User.objects.filter(email=user).exists():

但随后验证用户名

user = authenticate(username=user, password=password)

如果您使用的是电子邮件地址,则认证行应为

user = authenticate(email=user, password=password)