【问题标题】:Django password hasher with username in hashDjango密码散列器,用户名在散列中
【发布时间】:2014-12-11 23:44:37
【问题描述】:

也许是一个愚蠢的问题,但如果可能的话,使用用户名作为盐的一部分来编写 BasePasswordHasher 子类的最佳方法是什么?我正在从头开始重写一个网站,并在 php 中使用了这种方法。问题是在密码哈希中访问用户名。我真的很乐意解决这个问题,否则很多用户会丢失他们的密码,所以提前非常感谢!

PHP 代码:

function passHash($login, $pass)
{
    return md5(md5($pass).'salt'.$login);
}

【问题讨论】:

  • 你有这个原始算法吗?还有你到目前为止写的任何代码吗?
  • 编辑了原始问题以包含原始代码。还没有开始实施它,因为那不是问题。我开始阅读docs.djangoproject.com/en/dev/topics/auth/passwords 并看到输入不包含用户对象,或者我可以使用的任何东西。我很新@Django。
  • Python 有一个 MD5 模块 import md5,为了在 django 视图中获取用户对象,您必须使用 user_object = request.user 之类的东西来获取它(很多有趣的东西通过请求)在您拥有用户对象后,您可以从中获取很多信息,例如 user_object.username 或 user_object.is_authenticated()
  • 那么在登录过程的这个阶段request.user也是可用的吗?
  • 嗯。我可以肯定地说这是可能的——我曾经运行过一个 Django 网站,该网站通过收购与一家 Rails 商店合并,并获得了其他几家初创公司的用户群,它们都有自己的哈希机制——但它已经足够长了,我不记得任何细节。

标签: python django django-authentication password-hash


【解决方案1】:

正如您所注意到的,这不能仅在密码哈希中完成。密码散列器没有关于用户的信息,只有密码和散列。我认为你有两个选择。

首先,也许是最好的,是编写一个自定义的authentication backend。在身份验证后端级别,我们可以访问用户名和原始密码。它看起来像这样

# 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。然后您可以按计划编写自定义密码哈希。

【讨论】:

  • 还不知道为什么,但您必须在更新 try 块中的密码后调用 user.save(update_fields=['password']) 才能登录。也许你可以编辑答案。
  • @Kukosk 你是对的,这是我的疏忽。 user.set_password 不强制保存。我会编辑答案
【解决方案2】:

对于像我一样找到这篇文章的任何人,除了一件事之外,一切仍然按预期工作。在 Django 2.1 上,我发现我必须在 authenticate 方法中添加“请求”作为第一个参数。他们一定在某个时候通过了这个。我默默地失败了身份验证,不知道为什么。

【讨论】:

    猜你喜欢
    • 2017-05-10
    • 1970-01-01
    • 2022-12-19
    • 2012-07-06
    • 1970-01-01
    • 2020-11-09
    • 1970-01-01
    • 1970-01-01
    • 2016-06-06
    相关资源
    最近更新 更多