也许是一个愚蠢的问题,但如果可能的话,使用用户名作为盐的一部分来编写 BasePasswordHasher 子类的最佳方法是什么?我正在从头开始重写一个网站,并在 php 中使用了这种方法。问题是在密码哈希中访问用户名。我真的很乐意解决这个问题,否则很多用户会丢失他们的密码,所以提前非常感谢!
PHP代码:
function passHash($login, $pass)
{
return md5(md5($pass).'salt'.$login);
}
也许是一个愚蠢的问题,但如果可能的话,使用用户名作为盐的一部分来编写 BasePasswordHasher 子类的最佳方法是什么?我正在从头开始重写一个网站,并在 php 中使用了这种方法。问题是在密码哈希中访问用户名。我真的很乐意解决这个问题,否则很多用户会丢失他们的密码,所以提前非常感谢!
PHP代码:
function passHash($login, $pass)
{
return md5(md5($pass).'salt'.$login);
}
正如您所注意到的,这不能仅在密码哈希中完成。密码散列器没有关于用户的信息,只有密码和散列。我认为你有两个选择。
首先,可能是最好的,是编写一个自定义身份验证后端。在身份验证后端级别,我们可以访问用户名和原始密码。它看起来像这样
# settings.py
AUTHENTICATION_BACKENDS=(
'myapp.backends.LegacyBackend',
'django.contrib.auth.backends.ModelBackend',
)
# myapp.backends
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.utils.encoding import force_bytes
import hashlib
class LegacyBackend(ModelBackend):
# We only need to override the authenticate method
def authenticate(self, username=None, password=None, **kwargs):
# most of this is copied directly from ModelBackend's authenticate method
UserModel = get_user_model()
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel._default_manager.get_by_natural_key(username)
# This is the normal route that hands off to the password hasher pipeline
# but we will sidestep it entirely and verify the password here
#
# if user.check_password(password):
# return user
pwhash = hashlib.md5(force_bytes(password)).hexdigest()
hash = hashlib.md5(force_bytes(pwhash+"salt"+username)).hexdigest()
if hash == user.password:
# update the user's password if you want, so you can phase out this backend
user.set_password(password)
user.save(update_fields=["password"])
return user
except UserModel.DoesNotExist:
UserModel().set_password(password)
请注意,我尚未测试此代码,但它应该像宣传的那样工作。另外,你和新用户没有冲突,老用户的密码会更新为新的哈希算法(默认是PBKDF2+SHA256?不确定)。
第二种选择是编写一次性脚本来修改您的数据库,使user.password
字段看起来像legacymd5$username+salt$hash
. 然后您可以按计划编写自定义密码哈希。
对于像我一样找到这篇文章的任何人,除了一件事之外,一切仍然按预期工作。在 Django 2.1 上,我发现我必须在 authenticate 方法中添加“请求”作为第一个参数。他们一定在某个时候通过了这个。我默默地失败了身份验证,不知道为什么。