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

Django自定义认证系统check_password始终返回False问题求助

Django自定义认证系统check_password返回False的问题排查与修复

核心错误点分析

  • 模型类密码字段定义错误:自定义user类继承AbstractBaseUser时,手动定义了password = models.TextField(),直接覆盖了父类中用于存储哈希密码的字段。AbstractBaseUser的password字段会自动处理密码哈希存储,你手动定义的字段会存储明文密码,导致check_password()无法匹配哈希值。
  • 模型类缺少必要配置:继承AbstractBaseUser必须指定USERNAME_FIELD,否则Django无法识别用户名字段;另外last_login应该用DateTimeField而非DateField,需要与父类字段类型保持一致。
  • 认证后端方法缩进错误:get_user方法缩进在了authenticate方法内部,导致它不是类的成员方法,认证系统无法正确获取用户实例。
  • 认证后端未捕获用户不存在异常:user.objects.get(username=username)没有包裹在try-except块中,当用户不存在时会直接抛出异常,而非返回None。
  • 视图中认证方法调用方式错误:UserBackend.authenticate(ModelBackend(), ...)是错误的调用逻辑,authenticate是实例方法,必须先实例化UserBackend再调用。

修正后的models.py

from django.contrib.auth.models import AbstractBaseUser
from django.db import models

class User(AbstractBaseUser):
    # AbstractBaseUser已自带主键id,无需手动定义
    username = models.TextField(unique=True)  # 建议设置unique保证用户名唯一
    real_name = models.TextField()
    email = models.TextField()
    # 移除手动定义的password字段,使用父类的哈希处理字段
    description = models.TextField()
    last_login = models.DateTimeField(null=True, blank=True)  # 改为DateTimeField,允许空值
    created_at = models.DateField(auto_now_add=True)  # 自动生成创建时间

    class Meta:
        managed = False
        db_table = 'user'

    # 必须指定USERNAME_FIELD,告诉Django用哪个字段作为用户名标识
    USERNAME_FIELD = 'username'

    def __str__(self) -> str:
        return self.username

修正后的backends.py

from django.contrib.auth.backends import ModelBackend
from .models import User

class UserBackend(ModelBackend):
    def authenticate(self, **kwargs):
        username = kwargs.get('username')
        password = kwargs.get('password')

        if not username or not password:
            return None

        try:
            user_ = User.objects.get(username=username)
            if user_.check_password(password):
                return user_
        except User.DoesNotExist:
            return None

    # 修正缩进,成为类的成员方法
    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

修正后的views.py

from django.shortcuts import render, redirect
from django.contrib import messages
from .backends import UserBackend
from datetime import datetime

def signin(request):
    now = datetime.now()
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']

        # 正确实例化认证后端并调用authenticate方法
        backend = UserBackend()
        user = backend.authenticate(username=username, password=password)

        if user is not None:
            # 需导入django.contrib.auth并调用login完成登录
            # from django.contrib.auth import login
            # login(request, user)
            return redirect('/index')    
        else:
            messages.info(request, '无效的用户名或密码')
            return redirect("/signin")
    else:
        return render(request,'signin.html')

额外注意事项

  1. 数据库密码哈希更新:之前存储的明文密码需要重新生成哈希值存入数据库,可在Django Shell中执行以下代码处理:
from django.contrib.auth.hashers import make_password
from yourapp.models import User
user = User.objects.get(username='目标用户名')
user.password = make_password('原明文密码')
user.save()
  1. 配置认证后端:在项目settings.py中添加自定义后端:
AUTHENTICATION_BACKENDS = [
    'yourapp.backends.UserBackend',
    # 如需保留默认认证后端可继续添加
    # 'django.contrib.auth.backends.ModelBackend',
]
  1. 类名规范:Python类名建议使用大驼峰格式(如User而非user),符合PEP8编码规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 11:31:01