切换到django 3并返回django 2后无法登录Django项目
Posted
技术标签:
【中文标题】切换到django 3并返回django 2后无法登录Django项目【英文标题】:Can't login in Django project after switching to django 3 and return to django 2 【发布时间】:2021-11-20 17:38:06 【问题描述】:我有一个 Django 2.2 项目,它在一堆不同的服务器上运行,但它们使用相同的数据库。
我创建了一个分支来迁移到 Django 3,但并非所有服务器都会同时迁移。
我使用 Argon2:
# https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
]
当我在开发分支中切换到 django 3.2 时,一切正常。但是,当我回到 Django 2.2 时,我开始收到如下错误:
模板语法错误 填充不正确 (exception location: .../python3.6/base64.py in b64decode
)
只需删除 cookie 并重新加载即可解决这些问题。所以我猜测它们与 django 3.1 更改为 new default hashing algorithm 从 sha1 到 sha256 有关。
无论如何,重新加载后,页面工作正常。但是当我尝试登录时,它无法识别凭据。
然后我从备份中恢复了数据库并可以登录 django 2.2。
我再次尝试使用以下设置在 django 3.2 上运行:
DEFAULT_HASHING_ALGORITHM = 'sha1'
现在,当切换回 2.2 时,我在页面加载时没有收到错误(我不需要删除 cookie),但凭据仍然不起作用。
对我来说,切换到 django 3.2 后,数据库中密码的哈希值发生了变化。
django 3 是否有可能重写数据库中的密码? 任何人都可以指出解决方案或尝试的东西吗?
谢谢。
【问题讨论】:
【参考方案1】:解决方案 TL;DR
好吧,如果你使用 Argon2 哈希器,Django 确实会更新存储的密码,如果你想暂时避免它,你必须更新到 Django 3.1,直到准备好移动到 3.2 或子类化哈希器。
比较存储的密码
由于我在 Django 3 中可以访问生产数据库(django 2.2)和本地数据库,因此我比较了我的用户的密码:
Django 2.2(2019 年 4 月发布)
算法:argon2 类型:argon2i 版本:19 内存成本:512 时间成本: 2 并行度: 2 salt: UVn ********** hash: QVt ***** ************
Django 3.2
算法:argon2 品种:argon2id 版本:19 内存成本:102,400 时间成本: 2 并行度: 8 salt: pHQzc2 **************** hash: fj ****************
是的,它们是不同的!
Django 3.2 release notes 讲述默认 Argon2 哈希器的变化:
django.contrib.auth
PBKDF2 密码哈希的默认迭代次数从 216,000 增加到 260,000。
Argon2 密码哈希的默认变体已更改为 Argon2id。 memory_cost 和并行度增加到 102,400 和 8 分别匹配 argon2-cffi 默认值。
增加 memory_cost 会将所需内存从 512 KB 推到 100 MB。这仍然是相当保守的,但可能会导致问题 内存受限的环境。如果是这种情况,现有的 hasher 可以被子类化以覆盖默认值。
Argon2、MD5、PBKDF2、SHA-1 密码哈希器的默认盐熵从 71 位增加到 128 位。
这是改变的票:
#30472 Argon2id should be supported and become the default variety for Argon2PasswordHasher
并且查看django.contrib.auth.hashers
中的代码,我可以看到密码在check_password
上被修改:
def check_password(password, encoded, setter=None, preferred='default'):
...
hasher_changed = hasher.algorithm != preferred.algorithm
must_update = hasher_changed or preferred.must_update(encoded)
is_correct = hasher.verify(password, encoded)
...
class Argon2PasswordHasher(BasePasswordHasher):
...
def must_update(self, encoded):
decoded = self.decode(encoded)
current_params = decoded['params']
new_params = self.params()
...
def params(self):
argon2 = self._load_library()
# salt_len is a noop, because we provide our own salt.
return argon2.Parameters(
type=argon2.low_level.Type.ID,
version=argon2.low_level.ARGON2_VERSION,
salt_len=argon2.DEFAULT_RANDOM_SALT_LENGTH,
hash_len=argon2.DEFAULT_HASH_LENGTH,
time_cost=self.time_cost,
memory_cost=self.memory_cost,
parallelism=self.parallelism,
)
这一行type=argon2.low_level.Type.ID
将argon2 类型从argon2i
更改为argon2id
。其余的变化很明显。
我不确定这是否是真实的过程,但我猜它是这样的:
您输入密码 使用旧算法检查密码 如果匹配,则使用新算法重新散列并保存(如果我错了,我会很高兴)
回顾一下:我的问题
我的问题是我有几个不同的 Django 2 项目使用相同的公共核心代码和相同的数据库。 尽管它们是不同的项目,但有许多用户可以访问所有这些项目。 我想从最不敏感的地方开始逐步更新它们,看看是否出现错误。
解决方案 1
升级到 Django 3.1 而不是 3.2。这将允许我逐步更新不同的项目,而不会中断用户访问。 一旦所有项目在 3.1 版本中运行了一段时间并修复了出现的任何错误,我就可以更有信心地将它们同时更新到 django 3.2。这是我已经测试过并且有效的方法(它不会更改密码)。
解决方案 2
子类化 django.contrib.auth.hashers.Argon2PasswordHasher
哈希,因此它不会更新密码。在PASSWORD_HASHERS
设置中指向它,当所有项目在django 3.2中顺利运行时将其删除。
【讨论】:
以上是关于切换到django 3并返回django 2后无法登录Django项目的主要内容,如果未能解决你的问题,请参考以下文章
从 1.8 升级到 2.2.4 后,Django 无法创建用于单元测试的表