1

我想为使用 Google App Engine 的用户模型生成密码重置令牌。显然,我们不允许在 GAE 中轻松使用 Django,因此 Django 生成令牌的方法的原始代码是:

def _make_token_with_timestamp(self, user, timestamp):
    # timestamp is number of days since 2001-1-1.  Converted to
    # base 36, this gives us a 3 digit string until about 2121
    ts_b36 = int_to_base36(timestamp)

    # By hashing on the internal state of the user and using state
    # that is sure to change (the password salt will change as soon as
    # the password is set, at least for current Django auth, and
    # last_login will also change), we produce a hash that will be
    # invalid as soon as it is used.
    # We limit the hash to 20 chars to keep URL short
    key_salt = "django.contrib.auth.tokens.PasswordResetTokenGenerator"

    # Ensure results are consistent across DB backends
    login_timestamp = user.last_login.replace(microsecond=0, tzinfo=None)

    value = (unicode(user.id) + user.password +
            unicode(login_timestamp) + unicode(timestamp))
    hash = salted_hmac(key_salt, value).hexdigest()[::2]
    return "%s-%s" % (ts_b36, hash)

Python 不是我的专业语言,因此我需要一些帮助来编写类似于上述方法的自定义方法。我只有几个问题。首先,时间戳的目的是什么?Django 有自己的用户系统,而我使用的是我自己的简单自定义用户模型。我需要保留上述代码的哪些方面,我可以取消哪些方面?

4

1 回答 1

1

好吧,check_token- 方法看起来像这样:

def check_token(self, user, token):
    """
    Check that a password reset token is correct for a given user.
    """
    # Parse the token
    try:
        ts_b36, hash = token.split("-")
    except ValueError:
        return False

    try:
        ts = base36_to_int(ts_b36)
    except ValueError:
        return False

    # Check that the timestamp/uid has not been tampered with
    if not constant_time_compare(self._make_token_with_timestamp(user, ts), token):
        return False

    # Check the timestamp is within limit
    if (self._num_days(self._today()) - ts) > settings.PASSWORD_RESET_TIMEOUT_DAYS:
        return False

    return True
  • 首先将令牌的时间戳部分转换回整数
  • 然后使用该时间戳生成一个新令牌并与旧令牌进行比较。
    请注意,在生成令牌时,上次登录的时间戳是用于计算哈希的参数之一。这意味着在用户登录后,旧令牌将变得无效,这对于密码重置令牌是有意义的。
  • 最后执行检查以查看令牌是否已经超时。

这是一个相当简单的过程,也相当安全。如果您想使用重置系统闯入帐户,则必须知道用户的密码和上次登录时间戳才能计算哈希。如果你知道那不需要闯入帐户...

因此,如果您想制作这样的系统,重要的是在生成 hast 时使用不易猜测的参数,当然还要使用良好的加盐哈希函数。Django使用 sha1hashlib ,当然可以很容易地使用其他摘要。

另一种方法是生成一个随机密码重置令牌并将其存储在数据库中,但这可能会浪费大量空间,因为令牌列对于大多数用户来说可能是空的。

于 2012-05-19T19:35:43.020 回答