Django 中的密碼管理¶
密碼管理通常不應該不必要地重新發明,而 Django 致力於提供一套安全且靈活的工具來管理使用者密碼。本文檔描述了 Django 如何儲存密碼、如何配置儲存雜湊,以及一些用於處理雜湊密碼的實用工具。
另請參閱
即使使用者可能使用強密碼,攻擊者也可能能夠竊聽他們的連線。使用 HTTPS 以避免透過純 HTTP 連線傳送密碼(或任何其他敏感資料),因為它們容易受到密碼嗅探的攻擊。
Django 如何儲存密碼¶
Django 提供靈活的密碼儲存系統,預設使用 PBKDF2。
<algorithm>$<iterations>$<salt>$<hash>
這些是儲存使用者密碼所使用的元件,用錢字符號分隔,包含:雜湊演算法、演算法迭代次數(工作因素)、隨機鹽,以及產生的密碼雜湊。該演算法是 Django 可以使用的一系列單向雜湊或密碼儲存演算法之一;請參閱下文。迭代描述了該演算法在雜湊上執行的次數。鹽是使用的隨機種子,而雜湊是單向函式的結果。
預設情況下,Django 使用具有 SHA256 雜湊的 PBKDF2 演算法,這是一種密碼擴展機制,由 NIST 推薦。這對於大多數使用者來說應該足夠了:它非常安全,需要大量的計算時間才能破解。
但是,根據您的需求,您可以選擇不同的演算法,甚至使用自訂演算法來匹配您的特定安全情況。同樣,大多數使用者不需要這樣做 – 如果您不確定,您可能不需要。如果您需要,請繼續閱讀
Django 透過參考 PASSWORD_HASHERS
設定來選擇要使用的演算法。這是此 Django 安裝支援的雜湊演算法類別列表。
為了儲存密碼,Django 將使用 PASSWORD_HASHERS
中的第一個雜湊器。要使用不同的演算法儲存新密碼,請將您偏好的演算法放在 PASSWORD_HASHERS
中的第一位。
為了驗證密碼,Django 會在列表中找到與儲存密碼中的演算法名稱相符的雜湊器。如果儲存的密碼所用的演算法在 PASSWORD_HASHERS
中找不到,則嘗試驗證它將引發 ValueError
。
PASSWORD_HASHERS
的預設值為
PASSWORD_HASHERS = [
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
"django.contrib.auth.hashers.Argon2PasswordHasher",
"django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
"django.contrib.auth.hashers.ScryptPasswordHasher",
]
這表示 Django 將使用 PBKDF2 來儲存所有密碼,但會支援檢查以 PBKDF2SHA1、argon2 和 bcrypt 儲存的密碼。
接下來的幾節將介紹進階使用者可能想要修改此設定的幾種常見方式。
在 Django 中使用 Argon2¶
Argon2 是 2015 年 密碼雜湊競賽 的贏家,這是一場社群組織的公開競賽,旨在選出下一代雜湊演算法。它的設計目的不是在自訂硬體上比在普通 CPU 上更容易計算。Argon2 密碼雜湊器的預設變體是 Argon2id。
Argon2 不是 Django 的預設值,因為它需要第三方函式庫。但是,密碼雜湊競賽小組建議立即使用 Argon2,而不是 Django 支援的其他演算法。
若要使用 Argon2id 作為預設儲存演算法,請執行以下操作
安裝 argon2-cffi 套件。可以透過執行
python -m pip install django[argon2]
來完成,這相當於python -m pip install argon2-cffi
(以及 Django 的pyproject.toml
中的任何版本要求)。修改
PASSWORD_HASHERS
以將Argon2PasswordHasher
列在第一位。也就是說,在您的設定檔中,您會放入PASSWORD_HASHERS = [ "django.contrib.auth.hashers.Argon2PasswordHasher", "django.contrib.auth.hashers.PBKDF2PasswordHasher", "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", "django.contrib.auth.hashers.BCryptSHA256PasswordHasher", "django.contrib.auth.hashers.ScryptPasswordHasher", ]
如果您需要 Django 升級密碼,請保留及/或在此列表中新增任何項目。
在 Django 中使用 bcrypt
¶
Bcrypt 是一種流行的密碼儲存演算法,專門為長期密碼儲存而設計。它不是 Django 使用的預設值,因為它需要使用第三方函式庫,但由於許多人可能想要使用它,Django 可以透過最少的努力支援 bcrypt。
若要使用 Bcrypt 作為預設儲存演算法,請執行以下操作
安裝 bcrypt 套件。可以透過執行
python -m pip install django[bcrypt]
來完成,這相當於python -m pip install bcrypt
(以及 Django 的pyproject.toml
中的任何版本要求)。修改
PASSWORD_HASHERS
以將BCryptSHA256PasswordHasher
列在第一位。也就是說,在您的設定檔中,您會放入PASSWORD_HASHERS = [ "django.contrib.auth.hashers.BCryptSHA256PasswordHasher", "django.contrib.auth.hashers.PBKDF2PasswordHasher", "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", "django.contrib.auth.hashers.Argon2PasswordHasher", "django.contrib.auth.hashers.ScryptPasswordHasher", ]
如果您需要 Django 升級密碼,請保留及/或在此列表中新增任何項目。
就是這樣 – 現在您的 Django 安裝將使用 Bcrypt 作為預設儲存演算法。
在 Django 中使用 scrypt
¶
scrypt 與 PBKDF2 和 bcrypt 類似,它會使用設定好的迭代次數來減緩暴力攻擊。但是,由於 PBKDF2 和 bcrypt 不需要大量記憶體,因此擁有足夠資源的攻擊者可以發動大規模並行攻擊,以加快攻擊過程。scrypt 的設計目的是比其他基於密碼的金鑰衍生函式使用更多記憶體,以限制攻擊者可以使用的並行量,有關更多詳細資訊,請參閱 RFC 7914。
若要使用 scrypt 作為預設儲存演算法,請執行以下操作
修改
PASSWORD_HASHERS
以將ScryptPasswordHasher
列在第一位。也就是說,在您的設定檔中PASSWORD_HASHERS = [ "django.contrib.auth.hashers.ScryptPasswordHasher", "django.contrib.auth.hashers.PBKDF2PasswordHasher", "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", "django.contrib.auth.hashers.Argon2PasswordHasher", "django.contrib.auth.hashers.BCryptSHA256PasswordHasher", ]
如果您需要 Django 升級密碼,請保留及/或在此列表中新增任何項目。
注意
scrypt
需要 OpenSSL 1.1+。
增加鹽的熵¶
大多數密碼雜湊都包含鹽和密碼雜湊,以防止彩虹表攻擊。鹽本身是一個隨機值,它會增加彩虹表的大小,從而增加成本,目前在 BasePasswordHasher
中,使用 salt_entropy
值設定為 128 位。隨著計算和儲存成本的降低,這個值應該提高。當您實作自己的密碼雜湊器時,您可以自由地覆寫此值,以便為您的密碼雜湊使用所需的熵級別。salt_entropy
以位為單位測量。
實作細節
由於儲存鹽值的方法,salt_entropy
值實際上是一個最小值。例如,值為 128 時會提供一個實際上包含 131 位熵的鹽。
增加工作因素¶
PBKDF2 和 bcrypt¶
PBKDF2 和 bcrypt 演算法都使用多次迭代或多輪雜湊。這有意地減慢攻擊者的速度,使針對雜湊密碼的攻擊更加困難。然而,隨著運算能力的提高,迭代次數也需要增加。我們選擇了一個合理的預設值(並會在每個 Django 版本中增加它),但您可能希望根據您的安全需求和可用的處理能力來調整它。要做到這一點,您需要子類化適當的演算法並覆寫 iterations
參數(在子類化 bcrypt 雜湊器時使用 rounds
參數)。例如,要增加預設 PBKDF2 演算法使用的迭代次數
建立
django.contrib.auth.hashers.PBKDF2PasswordHasher
的子類別from django.contrib.auth.hashers import PBKDF2PasswordHasher class MyPBKDF2PasswordHasher(PBKDF2PasswordHasher): """ A subclass of PBKDF2PasswordHasher that uses 100 times more iterations. """ iterations = PBKDF2PasswordHasher.iterations * 100
將此子類別儲存在您專案中的某個位置。例如,您可以將其放在類似
myproject/hashers.py
的檔案中。將您的新雜湊器作為第一個條目新增到
PASSWORD_HASHERS
中PASSWORD_HASHERS = [ "myproject.hashers.MyPBKDF2PasswordHasher", "django.contrib.auth.hashers.PBKDF2PasswordHasher", "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", "django.contrib.auth.hashers.Argon2PasswordHasher", "django.contrib.auth.hashers.BCryptSHA256PasswordHasher", "django.contrib.auth.hashers.ScryptPasswordHasher", ]
就這樣 – 現在您的 Django 安裝在儲存使用 PBKDF2 的密碼時會使用更多的迭代次數。
注意
bcrypt rounds
是一個對數工作因子,例如,12 輪表示 2 ** 12
次迭代。
Argon2¶
Argon2 具有以下可自訂的屬性
time_cost
控制雜湊中的迭代次數。memory_cost
控制在計算雜湊期間必須使用的記憶體大小。parallelism
控制雜湊的計算可以平行處理多少個 CPU。
這些屬性的預設值可能適合您。如果您確定密碼雜湊速度太快或太慢,您可以按如下方式調整它
選擇
parallelism
為您可以空閒計算雜湊的執行緒數。選擇
memory_cost
為您可以空閒的記憶體 KiB 數。調整
time_cost
並測量雜湊密碼所需的時間。選擇一個對您來說可接受時間的time_cost
。如果將time_cost
設定為 1 會慢到無法接受,則降低memory_cost
。
memory_cost
的解讀
argon2 命令列工具和一些其他程式庫對 memory_cost
參數的解讀與 Django 使用的值不同。轉換由 memory_cost == 2 ** memory_cost_commandline
給出。
scrypt
¶
scrypt 具有以下可自訂的屬性
work_factor
控制雜湊中的迭代次數。block_size
parallelism
控制將平行執行多少個執行緒。maxmem
限制在計算雜湊期間可以使用的最大記憶體大小。預設值為0
,這表示來自 OpenSSL 程式庫的預設限制。
我們選擇了合理的預設值,但您可能希望根據您的安全需求和可用的處理能力來調整它。
估計記憶體使用量
scrypt 的最低記憶體需求為
work_factor * 2 * block_size * 64
因此,當變更 work_factor
或 block_size
值時,您可能需要調整 maxmem
。
密碼升級¶
當使用者登入時,如果他們的密碼是以非首選演算法儲存,Django 會自動將演算法升級為首選演算法。這表示舊版本的 Django 會在使用者登入時自動變得更安全,而且這也表示您可以在發明新的(且更好的)儲存演算法時切換到新的演算法。
但是,Django 只能升級使用 PASSWORD_HASHERS
中提及的演算法的密碼,因此,當您升級到新系統時,應確保永遠不要從此清單中移除條目。如果您這樣做,使用未提及演算法的使用者將無法升級。當增加(或減少)PBKDF2 迭代次數、bcrypt 輪數或 argon2 屬性時,雜湊密碼將會更新。
請注意,如果您的資料庫中的所有密碼不是以預設雜湊器的演算法編碼,則您可能會因為使用非預設演算法編碼的密碼的使用者的登入請求持續時間與不存在使用者(執行預設雜湊器)的登入請求持續時間之間的差異而容易受到使用者列舉時間攻擊。您可以透過升級較舊的密碼雜湊來減輕此問題。
無需登入即可進行密碼升級¶
如果您有一個現有的資料庫,其中包含較舊的弱雜湊(例如 MD5),您可能希望自己升級這些雜湊,而不是等待使用者登入時才進行升級(如果使用者沒有返回您的網站,則可能永遠不會發生)。在這種情況下,您可以使用「包裝」的密碼雜湊器。
在此範例中,我們將遷移 MD5 雜湊的集合以使用 PBKDF2(MD5(password)),並新增對應的密碼雜湊器以檢查使用者在登入時是否輸入了正確的密碼。我們假設我們使用的是內建的 User
模型,並且我們的專案有一個 accounts
應用程式。您可以修改此模式以使用任何演算法或自訂使用者模型。
首先,我們將新增自訂雜湊器
accounts/hashers.py
¶from django.contrib.auth.hashers import (
PBKDF2PasswordHasher,
MD5PasswordHasher,
)
class PBKDF2WrappedMD5PasswordHasher(PBKDF2PasswordHasher):
algorithm = "pbkdf2_wrapped_md5"
def encode_md5_hash(self, md5_hash, salt, iterations=None):
return super().encode(md5_hash, salt, iterations)
def encode(self, password, salt, iterations=None):
_, _, md5_hash = MD5PasswordHasher().encode(password, salt).split("$", 2)
return self.encode_md5_hash(md5_hash, salt, iterations)
資料遷移可能如下所示
accounts/migrations/0002_migrate_md5_passwords.py
¶from django.db import migrations
from ..hashers import PBKDF2WrappedMD5PasswordHasher
def forwards_func(apps, schema_editor):
User = apps.get_model("auth", "User")
users = User.objects.filter(password__startswith="md5$")
hasher = PBKDF2WrappedMD5PasswordHasher()
for user in users:
algorithm, salt, md5_hash = user.password.split("$", 2)
user.password = hasher.encode_md5_hash(md5_hash, salt)
user.save(update_fields=["password"])
class Migration(migrations.Migration):
dependencies = [
("accounts", "0001_initial"),
# replace this with the latest migration in contrib.auth
("auth", "####_migration_name"),
]
operations = [
migrations.RunPython(forwards_func),
]
請注意,此遷移對於數千名使用者來說將花費數分鐘的時間,具體時間取決於您的硬體速度。
最後,我們將新增 PASSWORD_HASHERS
設定
mysite/settings.py
¶PASSWORD_HASHERS = [
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"accounts.hashers.PBKDF2WrappedMD5PasswordHasher",
]
在此清單中包含您網站使用的任何其他雜湊器。
包含的雜湊器¶
Django 中包含的雜湊器完整清單為
[
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
"django.contrib.auth.hashers.Argon2PasswordHasher",
"django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
"django.contrib.auth.hashers.BCryptPasswordHasher",
"django.contrib.auth.hashers.ScryptPasswordHasher",
"django.contrib.auth.hashers.MD5PasswordHasher",
]
對應的演算法名稱為
pbkdf2_sha256
pbkdf2_sha1
argon2
bcrypt_sha256
bcrypt
scrypt
md5
撰寫您自己的雜湊器¶
如果您撰寫自己的密碼雜湊器,其中包含一個工作因子(例如迭代次數),您應該實作一個 harden_runtime(self, password, encoded)
方法,以彌合 encoded
密碼中提供的工作因子與雜湊器的預設工作因子之間的執行時間差距。這可防止由於使用較舊迭代次數編碼的密碼的使用者的登入請求與不存在使用者(執行雜湊器的預設迭代次數)之間的差異而導致的使用者列舉時間攻擊。
以 PBKDF2 為例,如果 encoded
包含 20,000 次迭代,而雜湊器的預設 iterations
為 30,000,則該方法應使 password
再執行 10,000 次 PBKDF2 迭代。
如果您的雜湊器沒有工作因子,請將該方法實作為空操作 (pass
)。
手動管理使用者的密碼¶
django.contrib.auth.hashers
模組提供一組用於建立和驗證雜湊密碼的函式。您可以獨立於 User
模型使用它們。
- acheck_password(password, encoded, asetter=None, preferred='default')¶
非同步版本:
acheck_password()
如果您想手動驗證使用者,方法是將純文字密碼與資料庫中已雜湊的密碼進行比較,請使用方便函式
check_password()
。它需要兩個強制性引數:要檢查的純文字密碼,以及使用者在資料庫中password
欄位的完整值,用來比對。如果它們匹配,則返回True
,否則返回False
。您可以選擇性地傳遞一個可呼叫的setter
,它接受密碼,並在您需要重新產生密碼時被呼叫。如果您不想使用預設值(PASSWORD_HASHERS
設定的第一個條目),您還可以傳遞preferred
來變更雜湊演算法。請參閱 包含的雜湊器 以取得每個雜湊器的演算法名稱。在 Django 5.0 中變更新增了
acheck_password()
方法。
- make_password(password, salt=None, hasher='default')[原始碼]¶
以這個應用程式使用的格式建立雜湊密碼。它需要一個強制性引數:純文字密碼(字串或位元組)。您可以選擇性地提供鹽和要使用的雜湊演算法,如果您不想使用預設值(
PASSWORD_HASHERS
設定的第一個條目)。請參閱 包含的雜湊器 以取得每個雜湊器的演算法名稱。如果密碼引數是None
,則會返回不可用的密碼(永遠不會被check_password()
接受的密碼)。
- is_password_usable(encoded_password)[原始碼]¶
如果密碼是
User.set_unusable_password()
的結果,則返回False
。
密碼驗證¶
使用者通常會選擇不好的密碼。為了幫助緩解這個問題,Django 提供了可外掛的密碼驗證。您可以同時設定多個密碼驗證器。Django 內建了一些驗證器,但您也可以編寫自己的驗證器。
每個密碼驗證器都必須提供說明文字來向使用者解釋需求,驗證給定的密碼,如果密碼不符合要求,則返回錯誤訊息,並且可以選擇性地定義一個回呼函式,以便在變更使用者的密碼時收到通知。驗證器還可以具有選擇性的設定來微調其行為。
驗證由 AUTH_PASSWORD_VALIDATORS
設定控制。該設定的預設值為空列表,這表示不應用任何驗證器。在使用預設 startproject
樣板建立的新專案中,預設會啟用一組驗證器。
預設情況下,驗證器用於重設或變更密碼的表單中,以及 createsuperuser
和 changepassword
管理命令中。驗證器不會應用於模型層級,例如在 User.objects.create_user()
和 create_superuser()
中,因為我們假設開發人員(而非使用者)會在該層級與 Django 互動,而且模型驗證不會自動作為建立模型的一部分執行。
注意
密碼驗證可以防止使用許多類型的弱密碼。但是,密碼通過所有驗證器的事實並不能保證它是強密碼。有許多因素會削弱密碼,即使是最先進的密碼驗證器也無法偵測到。
啟用密碼驗證¶
密碼驗證在 AUTH_PASSWORD_VALIDATORS
設定中配置
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
"OPTIONS": {
"min_length": 9,
},
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
此範例啟用了所有四個包含的驗證器
UserAttributeSimilarityValidator
,它會檢查密碼與使用者的一組屬性之間的相似性。MinimumLengthValidator
,它會檢查密碼是否符合最小長度。此驗證器使用自訂選項配置:現在要求最小長度為九個字元,而不是預設的八個字元。CommonPasswordValidator
,它會檢查密碼是否出現在常用密碼列表中。預設情況下,它會與包含的 20,000 個常用密碼列表進行比較。NumericPasswordValidator
,它會檢查密碼是否不是完全由數字組成。
對於 UserAttributeSimilarityValidator
和 CommonPasswordValidator
,我們在此範例中使用預設設定。NumericPasswordValidator
沒有設定。
密碼驗證器的說明文字和任何錯誤都會按照它們在 AUTH_PASSWORD_VALIDATORS
中列出的順序返回。
包含的驗證器¶
Django 包含四個驗證器
- class UserAttributeSimilarityValidator(user_attributes=DEFAULT_USER_ATTRIBUTES, max_similarity=0.7)[原始碼]¶
驗證密碼與使用者的某些屬性是否足夠不同。
user_attributes
參數應該是要與之比較的使用者屬性名稱的可迭代物件。如果未提供此引數,則使用預設值:'username'、'first_name'、'last_name'、'email'
。不存在的屬性會被忽略。密碼的最大允許相似度可以使用
max_similarity
參數設定為 0.1 到 1.0 的範圍。這會與difflib.SequenceMatcher.quick_ratio()
的結果進行比較。值為 0.1 會拒絕密碼,除非它們與user_attributes
有顯著差異,而值為 1.0 只會拒絕與屬性值相同的密碼。
- class CommonPasswordValidator(password_list_path=DEFAULT_PASSWORD_LIST_PATH)[原始碼]¶
驗證密碼不是常用密碼。這會將密碼轉換為小寫(進行不區分大小寫的比較),並根據 Royce Williams 建立的 20,000 個常用密碼的列表進行檢查。
password_list_path
可以設定為常用密碼的自訂檔案路徑。此檔案應包含每行一個小寫密碼,並且可以是純文字或 gzip 壓縮的。
整合驗證¶
在 django.contrib.auth.password_validation
中有一些函式,您可以從自己的表單或其他程式碼中呼叫,以整合密碼驗證功能。如果您使用自訂表單來設定密碼,或者如果您有允許設定密碼的 API 呼叫時,這會很有用。
- validate_password(password, user=None, password_validators=None)[原始碼]¶
驗證密碼。如果所有驗證器都認為密碼有效,則返回
None
。如果有一個或多個驗證器拒絕密碼,則會引發一個ValidationError
異常,其中包含來自驗證器的所有錯誤訊息。user
物件是可選的:如果未提供,則某些驗證器可能無法執行任何驗證,並且將接受任何密碼。
- password_changed(password, user=None, password_validators=None)[原始碼]¶
通知所有驗證器密碼已變更。驗證器可以使用此功能,例如防止密碼重複使用。密碼成功變更後,應呼叫此函式一次。
對於
AbstractBaseUser
的子類別,當呼叫set_password()
時,密碼欄位將被標記為「已變更」,這會在使用者儲存後觸發對password_changed()
的呼叫。
- password_validators_help_text_html(password_validators=None)¶
返回一個 HTML 字串,其中包含
<ul>
中的所有幫助文字。當向表單添加密碼驗證時,這很有用,因為您可以將輸出直接傳遞到表單欄位的help_text
參數。
- get_password_validators(validator_config)[原始碼]¶
根據
validator_config
參數返回一組驗證器物件。預設情況下,所有函式都使用在AUTH_PASSWORD_VALIDATORS
中定義的驗證器,但是通過使用另一組驗證器呼叫此函式,然後將結果傳遞給其他函式的password_validators
參數,將會使用您的自訂驗證器集。當您在大多數情況下都使用一組典型的驗證器,但也有需要自訂集驗證器的特殊情況時,這會很有用。如果您始終使用相同的驗證器集,則無需使用此函式,因為預設情況下會使用來自AUTH_PASSWORD_VALIDATORS
的配置。validator_config
的結構與AUTH_PASSWORD_VALIDATORS
的結構相同。此函式的傳回值可以傳遞到上面列出的函式的password_validators
參數中。
請注意,將密碼傳遞到這些函式之一時,它應該始終是明文密碼,而不是雜湊密碼。
編寫自己的驗證器¶
如果 Django 的內建驗證器不足,您可以編寫自己的密碼驗證器。驗證器具有相當小的介面。它們必須實作兩個方法
validate(self, password, user=None)
:驗證密碼。如果密碼有效,則返回None
,如果密碼無效,則引發帶有錯誤訊息的ValidationError
。您必須能夠處理user
為None
的情況 - 如果這表示您的驗證器無法執行,則返回None
表示沒有錯誤。get_help_text()
:提供幫助文字,向使用者說明要求。
在 AUTH_PASSWORD_VALIDATORS
中,驗證器的 OPTIONS
中的任何項目都將傳遞給建構子。所有建構子參數都應具有預設值。
以下是一個具有一個可選設定的驗證器的基本範例
from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _
class MinimumLengthValidator:
def __init__(self, min_length=8):
self.min_length = min_length
def validate(self, password, user=None):
if len(password) < self.min_length:
raise ValidationError(
_("This password must contain at least %(min_length)d characters."),
code="password_too_short",
params={"min_length": self.min_length},
)
def get_help_text(self):
return _(
"Your password must contain at least %(min_length)d characters."
% {"min_length": self.min_length}
)
您也可以實作 password_changed(password, user=None
),這會在密碼成功變更後呼叫。例如,這可以用來防止密碼重複使用。但是,如果您決定儲存使用者的先前密碼,則絕不應以明文形式儲存。