django用户密码应直接使用set_password()和check_password(),因其内置带盐哈希、自动升级、兼容认证生态;手写hash会丢失salt唯一性、格式识别、自动升级等关键能力。

Django 自带的用户密码存储机制就是安全的,不需要你额外“安全存储”——直接用 set_password() 和 check_password(),别自己手写哈希逻辑。
为什么不能自己用 hashlib 加密密码?
Django 用户密码不是简单哈希,而是带盐(salt)、可调迭代次数、支持算法升级的完整凭证体系。你自己用 hashlib.pbkdf2_hmac() 或 bcrypt.hashpw() 手动处理,会丢失以下关键能力:
- 每次调用
set_password()自动生成唯一 salt,而手写容易复用 salt 或硬编码 - Django 能识别旧哈希格式(如
pbkdf2_sha256$36000$...),登录时自动升级;手写哈希无法被check_password()识别 - 管理员重置密码、
createsuperuser、第三方认证后端(如 social-auth)全部依赖 Django 的密码协议
set_password() 和 check_password() 怎么用才不踩坑?
这两个方法只在 User 实例上生效,不是静态工具函数。常见错误是传错对象或绕过 ORM:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- ✅ 正确:
user.set_password("newpass123"); user.save()—— 必须save(),否则密码字段没写入数据库 - ❌ 错误:
User.objects.filter(...).update(password=...)—— 直接 update 会写入明文或未处理的哈希,跳过 Django 密码逻辑 - ❌ 错误:
user.password = "newpass123"; user.save()—— 这等于存明文,set_password()不仅哈希还清理 session、重置last_login等副作用 - 验证必须用
user.check_password("input"),不能用==比较字符串
自定义用户模型时密码字段还能用吗?
能,但必须继承 AbstractBaseUser 并显式声明 password 字段,且保留 set_password 和 check_password 方法:
class MyUser(AbstractBaseUser):
password = models.CharField(_("password"), max_length=128) # 必须保留此字段名
# ...其他字段
def set_password(self, raw_password):
super().set_password(raw_password) # 调用父类实现
def check_password(self, raw_password):
return super().check_password(raw_password)
如果删掉 password 字段或重命名,Django 认不出这是密码字段,authenticate()、管理后台登录、create_user() 全部失效。
真正需要额外防护的不是密码存储本身,而是传输(强制 HTTPS)、输入(前端不存明文、禁用 autocomplete)、日志(确保 LOGGING 配置不记录 password 字段)、数据库权限(限制非必要账号读取 auth_user.password)。密码哈希只是最后一道锁,钥匙早该在别的环节就管住了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










