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')
额外注意事项
- 数据库密码哈希更新:之前存储的明文密码需要重新生成哈希值存入数据库,可在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()
- 配置认证后端:在项目
settings.py中添加自定义后端:
AUTHENTICATION_BACKENDS = [ 'yourapp.backends.UserBackend', # 如需保留默认认证后端可继续添加 # 'django.contrib.auth.backends.ModelBackend', ]
- 类名规范:Python类名建议使用大驼峰格式(如
User而非user),符合PEP8编码规范。
内容的提问来源于stack exchange,提问作者Dirky
相关产品推荐
相关产品推荐

