我们如何修补 Django 以保持用户在会话之间登录

How we patched Django to keep users logged in between sessions

我们在使用 Django 的网站上遇到了问题。每次我们升级 Django 时,如果用户使用两个或多个不同的浏览器登录,然后他们从一个浏览器再次登录 - 他们会自动从所有其他会话(浏览器)注销。由于我们在去年将 Django 升级到新的主要版本大约 5 次,这让我们很头疼。我们不想强迫用户必须在会话之间一次又一次地登录。我们如何解决这个问题?

我们查了一下,这个问题是由于Django版本之间PBKDF2PasswordHasher.iterations的变化引起的。每次我们将 Django 升级到新的主要版本(例如从 3.0 到 3.1)时,PBKDF2PasswordHasher.iterations 都会发生变化。这会导致用户下次登录时再次计算用户的散列密码,从而强制用户在所有其他会话中保持注销状态。我什至用 Django 的跟踪系统创建了一个 ticket

有两种方法可以解决这个问题。首先,我们可以修补 class PBKDF2PasswordHasher 以保持 iterations 的数量不变,同时更新 def must_update:

from django.contrib.auth.hashers import PBKDF2PasswordHasher


def patch():
    def must_update(self, encoded):
        # Update the stored password only if the iterations diff is at least 250,000.
        algorithm, iterations, salt, hash = encoded.split('$', 3)
        iterations_diff = abs(self.iterations - int(iterations))
        return ((int(iterations) != self.iterations) and (iterations_diff >= 250000))

    PBKDF2PasswordHasher.iterations = 180000  # Django 3.0.x
    PBKDF2PasswordHasher.must_update = must_update

然后在我们基地AppConfigclass:

class SpeedyCoreBaseConfig(AppConfig):
    name = 'speedy.core.base'
    verbose_name = _("Speedy Core Base App")
    label = 'base'

    def ready(self):
        locale_patches.patch()  # Another patch
        session_patches.patch()  # This patch

或者,您可以从 PBKDF2PasswordHasher 继承新的 class,更改 iterationsdef must_update,并在设置中使用新的 class ( PASSWORD_HASHERS)。我们使用了第一个选项,尽管从软件工程的角度来看使用第二个选项(继承一个新的 class)可能会更好。他们都工作。