【问题标题】:Authenticate user using email and password使用电子邮件和密码对用户进行身份验证
【发布时间】:2013-05-18 15:03:36
【问题描述】:

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

首先,这不是与通过电子邮件登录有关的任何问题的重复,因为在我的场景中,我在 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

有人可以帮帮我吗?

【问题讨论】:

    标签: django


    【解决方案1】:

    正如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})
    

    【讨论】:

    • @JackRoster 我更新了我的答案并提供了完整的工作示例。谢谢
    • 没问题。如果这对你有帮助,那对我来说很重要:)
    【解决方案2】:

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

    # 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',
    )
    

    【讨论】:

      【解决方案3】:

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

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

      然后根据用户名进行验证

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

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

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

      【讨论】:

      • 它不允许您通过电子邮件进行身份验证
      • 谢谢,我只是在看代码本身(对他使用的后端没有真正的了解,但很明显比较不同)。希望有一天我会有足够的积分来实际制作 cmets 而无需回答:-)
      猜你喜欢
      • 2020-09-13
      • 2019-06-11
      • 1970-01-01
      • 2018-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-03
      相关资源
      最近更新 更多