Django从3版本回退至2版本后项目无法登录问题咨询
核心问题解答
Django 3确实会改写数据库中存储的密码哈希值,触发逻辑是:当用户输入明文密码登录、校验通过后,如果Django检测到当前存储的哈希使用的算法/参数,与配置中排在首位的哈希器的算法/参数不一致,就会自动用首位哈希器重新计算哈希并覆盖写入数据库。
你遇到的登录校验失败本质是Django 2.2和3.2的密码哈希参数不兼容,再加上跨版本自动升级哈希导致的。
问题根因拆解
- Cookie报错问题确实和默认哈希算法切换有关:Django 3.1+默认用sha256做会话签名,生成的Cookie无法被Django 2.2解析,你添加
DEFAULT_HASHING_ALGORITHM = 'sha1'的操作已经解决了这个问题。 - 登录失败的根因是两个版本的Argon2默认参数不一致:Django 3.x对Argon2PasswordHasher的默认参数(时间成本、内存成本、并行数等)做了更新,和Django 2.2的默认参数不匹配。当用户在Django 3.2环境下登录时,系统会自动把旧参数生成的哈希升级为新参数的版本,这个新哈希无法被Django 2.2的哈希器校验通过。
可行解决方案
1. 过渡期临时禁用哈希自动升级(优先选,适合多版本共存阶段)
在Django 3.2的项目中自定义固定参数的Argon2哈希器,完全对齐Django 2.2的默认参数,同时关闭自动升级逻辑:
# 首先确认Django 2.2中Argon2PasswordHasher的默认参数,示例如下(以实际源码为准) from django.contrib.auth.hashers import Argon2PasswordHasher class CompatArgon2PasswordHasher(Argon2PasswordHasher): time_cost = 2 # Django 2.2默认值 memory_cost = 102400 # Django 2.2默认值 parallelism = 8 # Django 2.2默认值 hash_len = 16 salt_len = 16 def must_update(self, encoded): # 强制不升级哈希,避免覆盖写入旧版本不兼容的哈希 return False # 然后把自定义哈希器放在PASSWORD_HASHERS的第一位 PASSWORD_HASHERS = [ 'your.path.CompatArgon2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher', ]
等所有服务器都完成Django 3.2的迁移后,再移除must_update的重写,即可正常启用哈希自动升级逻辑。
2. 流量隔离方案
如果担心测试环境影响生产数据,过渡期可以给Django 3.2的测试实例单独配测试数据库,不要直接连生产库,等兼容性验证完成后再切生产流量。
调试方向
- 对比同一账号在备份库和故障库中的密码哈希值:如果哈希的参数段(
$argon2id$v=19$m=xxx,t=xxx,p=xxx$部分)不一致,即可确认是哈希自动升级导致的问题。 - 分别在Django 2.2和3.2环境下,用同一个明文密码生成哈希,对比格式是否完全一致,排查参数差异。
- 校验两个环境下
argon2-cffi依赖库的版本,版本差异也可能导致默认参数不兼容。
内容的提问来源于stack exchange,提问作者equalium
相关产品推荐
相关产品推荐

