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

Django3.0自定义用户模型authenticate返回None问题排查求助

问题分析与解决方案

首先,你的代码里有两个关键问题导致authenticate()始终返回None,咱们一步步来解决:

1. 用户管理器里的递归调用错误

在AccountManager的create_user方法中,你错误地用self.create_user()来创建用户实例——这是递归调用自己,会导致代码根本走不到set_password()那一步!最终密码没有被正确哈希存储(甚至等于没设置密码),这直接导致authenticate()无法匹配验证。

修复方法:

把创建用户实例的代码改成self.model()(这是BaseUserManager提供的标准方法,用来获取当前管理器对应的用户模型):

class AccountManager(BaseUserManager):
    def create_user(self, email, username, password=None):
        if not email:
            raise ValueError("Email Id not entered")
        if not username:
            raise ValueError("User Name not entered")
        # 替换递归调用为self.model()创建实例
        user = self.model(
            email=self.normalize_email(email),
            username=username,
        )
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, username, password):
        user = self.create_user(
            email=self.normalize_email(email),
            password=password,
            username=username,
        )
        user.is_admin = True
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)
        return user

2. 登录视图的表单验证语法错误

在login视图里,你写了if form.is_valid——这其实是在判断is_valid这个方法对象是否存在(永远为True),而不是真正执行表单验证逻辑。正确的写法是调用方法form.is_valid()。

修复方法:

修改登录视图中的判断逻辑:

def login(request):
    context = {}
    if request.method == "POST":
        form = AuthenticationForm(request.POST)
        # 修复:添加括号调用is_valid()方法
        if form.is_valid():
            name = request.POST["username"]
            pswd = request.POST["password"]
            user = authenticate(request, username=name, password=pswd)
            print("user = " + str(user))
            if user:
                print("valid user " + str(user))
                login(request, user)
                print("user is " + str(request.user.is_authenticated))
                return redirect("../dashboard/")
    form = AuthenticationForm()
    context['login_form'] = form
    return render(request, 'login.html', context)

额外优化建议

AuthenticationForm默认是为Django内置的User模型设计的,对于自定义用户模型,最好创建一个适配的表单子类,避免潜在问题:

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

class CustomAuthenticationForm(AuthenticationForm):
    class Meta:
        model = Account
        fields = ['username', 'password']

之后在登录视图里替换成这个自定义表单即可:

form = CustomAuthenticationForm(request.POST)

验证修复效果

  1. 先删除之前注册的测试用户(因为它们的密码是明文存储的,不符合规范)
  2. 重新注册一个用户
  3. 尝试登录,此时authenticate()应该能正确返回用户实例了

另外你提到Account.objects.get(username="uname").password和request.POST['password']对比为True,这正好说明之前的密码是明文存储的(因为set_password()没执行),修复后数据库里的密码会变成哈希值,此时直接对比就不会相等了——这才是正确的安全状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 15:02:38