Django用户模型:save()方法中密码更改的目的是什么

时间:2019-10-07 08:17:06

标签: django django-authentication

有时我想以编程方式设置密码。我执行以下操作:

https://docs.djangoproject.com/en/2.2/topics/auth/default/#changing-passwords
You can also change a password programmatically, using set_password():

from django.contrib.auth.models import User
u = User.objects.get(username='john')
u.set_password('new pass')
u.save()

我想看看在运行u.save()时在save()中是如何实现的

基本上,我试图了解AbstractBaseUser中使用的save()方法

# ./.venv/lib/python3.7/site-packages/django/contrib/auth/base_user.py
class AbstractBaseUser(models.Model):
    password = models.CharField(_('password'), max_length=128)

    ........

    # Stores the raw password if set_password() is called so that it can
    # be passed to password_changed() after the model is saved.
    _password = None


    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        if self._password is not None:
            password_validation.password_changed(self._password, self)
            self._password = None

    ........

    def set_password(self, raw_password):
        self.password = make_password(raw_password)
        self._password = raw_password

def save(self, *args, **kwargs):

super().save(*args, **kwargs)

将保存由set_password设置的密码,该密码将在验证密码的下一行password_validation.password_changed之前

那先保存密码然后再进行验证有什么意义,因为它已经进入数据库了。

1 个答案:

答案 0 :(得分:1)

password_validation.password_changed并没有您认为的那样。

通过调用django.contrib.auth.password_validation.validate_password方法,在保存User对象之前完成了实际的密码验证。 此方法调用设置AUTH_PASSWORD_VALIDATORS中的每个验证器,并在这些验证器中的任何一个失败时引发异常。这可以是任何一种验证方式,例如新密码是否足够复杂,或者与用户名是否足够不同。

根据the docs

  

默认情况下,表单中使用验证器来重置或更改   密码以及在createsuperuser和changepassword管理中   命令。

     

验证者未应用于模型级别,例如   User.objects.create_user()和create_superuser(),因为我们假设   开发人员(而不是用户)在该级别与Django进行交互,并且   还因为模型验证不会自动作为   创建模型。

因此,用户保存模型不会对用户密码进行任何验证,而表单和命令会进行验证。如果您在某处代码中手动设置了密码,请确保自己进行验证。

那么password_validation.password_changed(self._password, self)会做什么?

简单地说,它会通知所有活动的验证者用户已更改了密码以及实际的 raw 新密码。为什么这是必要的?假设我编写了一个验证程序,用于检查用户是否尝试将其密码更改为以前使用的密码。该验证程序将需要知道用户过去使用过哪些密码,因此我需要保存每个用户的(散列)原始密码列表。

password_changed基本上是Django对所有密码验证程序说的一种方法:“嘿,请注意,用户的密码已更改为该值,因此如果您需要跟踪某些密码,原因,现在就做,因为在此之后,我将销毁该密码的未加密版本”