You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django自定义邮箱用户登录时authenticate返回None问题排查

问题根源及修复方案

你的代码存在几个关键错误,导致authenticate返回None:

1. 登录时错误加密用户输入的密码

在LoginView的form_valid方法中,你对用户输入的明文密码再次调用make_password加密,然后传给authenticate。但user.check_password()方法需要接收明文密码,与数据库中已存储的加密密码进行比对,这会导致密码永远不匹配。

修复LoginView:

class LoginView(FormView):
    template_name = 'login.html'
    form_class    = LoginForm 

    def form_valid(self, form):
        email    = form.cleaned_data['email']
        # 直接使用明文密码,不要加密
        password = form.cleaned_data['password']
        print(email, password)
        # 调用authenticate时传入email参数(匹配你的后端定义)
        user     = authenticate(request=self.request, email=email, password=password)
        print(user)
        if user is not None:
            print('do')
            login(self.request, user)
            return redirect('home')
        else:
            messages.info(self.request, 'invalid username or password')
            return redirect('login')

2. 注册时手动处理密码的方式错误

在SignUp视图中,你手动调用make_password处理密码,并且直接实例化User对象保存,这种方式不符合Django用户创建的规范,同时调用authenticate时传入了加密后的密码,导致验证失败。

修复SignUpView:

UserCreationForm的save()方法会自动处理密码加密和用户创建,无需手动操作:

class SignUp(CreateView):
    form_class    = SignUpForm
    template_name = 'signup.html' 
    
    def form_valid(self, form):
        # 直接保存表单,自动处理密码加密
        user = form.save()
        print("User created!")
        # 用明文密码调用authenticate
        user = authenticate(request=self.request, email=user.email, password=form.cleaned_data['password1'])
        login(self.request, user)
        return redirect('home')

3. 自定义认证后端的参数兼容性优化

当前你的EmailBackend只接收email参数,但Django的authenticate有时会传入username参数(比如admin后台登录),可以优化后端使其兼容两种参数:

class EmailBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, email=None, **kwargs):
        UserModel = get_user_model()
        # 优先使用email参数,没有则用username(因为USERNAME_FIELD是email)
        login_email = email or username
        try:
            user = UserModel.objects.get(email=login_email)
        except UserModel.DoesNotExist:
            return None
        else:
            if user.check_password(password):
                return user
        return None

额外优化:LoginForm字段类型修正

你的LoginForm中email字段用了forms.CharField,应该改为forms.EmailField以确保邮箱格式验证:

class LoginForm(forms.Form):
    # 改为EmailField
    email     = forms.EmailField(widget=forms.EmailInput(
        attrs={'class'      : 'form-control', 
               'type'       : "text",
               'placeholder': "Email"}))
    # 其余代码不变...

完成以上修复后,authenticate应该能正确返回用户对象,登录功能即可正常工作。

内容的提问来源于stack exchange,提问作者Omnia Osman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 15:44:50