Django中check_password返回True但authenticate返回None的问题排查
问题:Django登录接口authenticate返回None但check_password正常的问题
我用Django内置功能编写登录接口的单元测试,账号创建接口功能已确认正常,但在登录视图中,check_password()函数返回True,authenticate()却返回None。请问能否安全使用check_password()替代?若不能,该如何修改代码以使用authenticate()?
注:已确认用户is_active字段为True。
相关代码
accounts.py
class Account(AbstractUser): username = models.CharField(max_length=150, unique=True, null=False, default='') password = models.CharField(max_length=100) ... REQUIRED_FIELDS = ['username', 'password'] class Meta: app_label = 'accounts' db_table = 'accounts_account' objects = models.Manager()
test_login.py
def test_login(self): # Create account request_create = self.factory.post('/accounts/account', self.request_data, content_type='application/json') view = AccountView.as_view() response_create = view(request_create) # Login account request_login = self.factory.post('/accounts/login', self.request_data, content_type='application/json') view = LoginView.as_view() response = view(request_login)
views.py
class LoginView(View): def post(self, request): r = json.loads(request.body) username = r.get('username') password = r.get('password') cp = check_password(password, Account.objects.get(username=username).password) user = authenticate(username=username, password=password)
解答
1. 绝对不能用check_password()替代authenticate()
check_password()仅做密码哈希值的匹配验证,但authenticate()是Django认证系统的核心入口,它会处理:
- 验证用户
is_active状态(你已确认正常,但还有其他逻辑) - 支持多认证后端的扩展逻辑
- 触发
user_logged_in等认证相关信号 - 后续调用
login()函数必须依赖authenticate()返回的用户对象,直接用check_password()通过的用户登录,会跳过认证系统的安全校验,存在风险且不符合Django规范。
2. 修复authenticate()返回None的问题
问题根源在你的Account模型:手动重新定义了password字段,覆盖了AbstractUser自带的password字段逻辑。
AbstractUser的password字段会自动处理密码的哈希存储,而你手动定义的CharField会直接存储明文(或未正确哈希的内容)。这就导致:
check_password()能匹配是因为直接拿输入和存储的内容做对比authenticate()会用标准的密码哈希验证逻辑,自然匹配失败返回None
具体修复步骤:
- 删除
Account模型中手动定义的password字段:
class Account(AbstractUser): username = models.CharField(max_length=150, unique=True, null=False, default='') # 移除这一行:password = models.CharField(max_length=100) ...
- 确保账号创建视图
AccountView中,用Django提供的set_password()方法设置密码,而不是直接赋值:
# 示例:AccountView创建用户的核心逻辑 username = r.get('username') password = r.get('password') user = Account(username=username) user.set_password(password) # 该方法会自动哈希密码 user.save()
- 清空测试数据库后重新运行测试,确保新创建的用户密码是正确哈希存储的。
完成以上修改后,authenticate(username=username, password=password)就能正常返回用户对象了。
内容的提问来源于stack exchange,提问作者ang
相关产品推荐
相关产品推荐

