有时我想以编程方式设置密码。我执行以下操作:
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
之前
那先保存密码然后再进行验证有什么意义,因为它已经进入数据库了。
答案 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对所有密码验证程序说的一种方法:“嘿,请注意,用户的密码已更改为该值,因此如果您需要跟踪某些密码,原因,现在就做,因为在此之后,我将销毁该密码的未加密版本”