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

Django自定义AuthenticationForm:仅邮箱密码登录异常排查

仅用邮箱和密码实现Django用户认证的解决方案

核心问题分析

你的代码存在三个关键问题导致表单带username字段且验证失败:

  1. AuthenticationForm默认自带username字段,继承后未主动移除;
  2. 表单的__init__方法调用父类时参数错误,导致自定义字段未正确初始化;
  3. 登录视图中错误地将表单传入login函数,login需要的是认证后的用户对象而非表单。

1. 修复自定义登录表单UserLoginForm

AuthenticationForm并非ModelForm,所以Meta类的fields设置无效。直接移除默认的username字段,并重写表单字段:

from django.contrib.auth.forms import AuthenticationForm
from django import forms

class UserLoginForm(AuthenticationForm):
    # 显式移除默认的username字段
    username = None
    
    _base_attrs = {
        'class': 'form-control', 
        'placeholder': '', 
    }
    
    email = forms.EmailField(
        widget=forms.TextInput(attrs=_base_attrs)
    )
    password = forms.CharField(
        widget=forms.PasswordInput(attrs=_base_attrs)
    )
    
    def __init__(self, *args, **kwargs):
        # 正确调用父类初始化方法
        super().__init__(*args, **kwargs)

2. 修复认证后端EmailBackend

原后端未处理邮箱不存在的情况,会抛出异常,同时必须实现get_user方法(Django认证后端的强制要求):

from django.contrib.auth.backends import BaseBackend
from django.contrib.auth import get_user_model

class EmailBackend(BaseBackend):
    def authenticate(self, request, email=None, password=None):
        UserModel = get_user_model()
        try:
            user = UserModel.objects.get(email=email)
        except UserModel.DoesNotExist:
            # 邮箱不存在时返回None,避免崩溃
            return None
        
        # 验证密码且用户状态激活
        if user.check_password(password) and user.is_active:
            return user
        return None
    
    def get_user(self, user_id):
        UserModel = get_user_model()
        try:
            return UserModel.objects.get(pk=user_id)
        except UserModel.DoesNotExist:
            return None

3. 修复登录视图login_view

login函数需要传入认证后的用户对象,需先通过authenticate验证邮箱和密码:

from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate
from .forms import UserLoginForm

def login_view(request):
    if request.method == "POST":
        form = UserLoginForm(request.POST)
        if form.is_valid():
            # 从表单获取清洗后的邮箱和密码
            email = form.cleaned_data['email']
            password = form.cleaned_data['password']
            # 调用自定义后端认证用户
            user = authenticate(request, email=email, password=password)
            if user:
                login(request, user)
                return redirect('home')
    else:
        form = UserLoginForm()
    
    return render(request, 'login.html', {'form': form})

4. 额外优化点

  • 用户模型中REQUIRED_FIELDS不需要包含password(AbstractBaseUser默认处理密码字段),可改为:
    REQUIRED_FIELDS = []
    
  • 确保settings.py中的配置正确:
    AUTH_USER_MODEL = 'account.User'
    AUTHENTICATION_BACKENDS = ['account.backends.EmailBackend']
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 06:04:58