tp6密码自动哈希必须用严格驼峰的setpasswordattr,且模型须继承think\model;若失效,常见原因为模型类错误、方法名不规范或绕过模型直接update;应使用password_hash()加密并用password_verify()验证。

TP6 的密码字段自动哈希必须用 setPasswordAttr,不能写 _setAttr 或依赖旧版 $filter,否则加密逻辑根本不会触发。
为什么 setPasswordAttr 不生效?
常见现象是调用 $user->save() 后数据库里还是明文。根本原因不是代码写错,而是模型没对上路:
- 模型类没继承
think\Model(比如误用了think\db\Model) - 方法名写成
setpasswordattr或SetPasswordAttr—— 必须严格驼峰:setPasswordAttr - 数据库字段叫
pwd,但方法却写成了setPasswordAttr;字段名和方法前缀必须完全一致 - 用
$model->where()->update(['password' => '123456'])这种方式绕过了模型,修改器天然不触发
怎么写一个安全可用的 setPasswordAttr?
别再用 md5() 或拼接盐值,直接用 PHP 原生 password_hash(),它自动处理盐、算法升级和轮数控制:
public function setPasswordAttr($value)
{
if (empty($value)) {
return null;
}
if (strlen($value) 72) {
throw new \InvalidArgumentException('密码长度必须为 8–72 字符');
}
return password_hash($value, PASSWORD_DEFAULT, ['cost' => 12]);
}
注意点:
-
PASSWORD_DEFAULT是当前最稳妥的选择,PHP 升级后会自动切到更安全算法 -
cost => 12比默认 10 更抗暴力破解,又不至于让登录接口明显变慢 - 务必判空并拦截超长输入,
password_hash(null)返回false,会导致入库失败
setPasswordAttr 里能访问其他字段吗?
不能依赖 $this->email 或 $this->getData() 获取上下文数据。修改器执行时模型状态不稳定,字段可能还没赋值或仍是旧值。
如果业务真需要“用户名+密码”组合加盐,或者根据角色动态选哈希算法,就别硬塞进修改器——改用 onBeforeInsert 静态事件,或重写 save() 方法,在完整数据准备好后再统一处理。
验证时千万别自己比对哈希字符串
存库用 password_hash(),读库后验证必须用 password_verify($input, $hash)。写成 $hash === password_hash($input, ...) 或 hash_equals() 手动比对,都会失败——因为每次 password_hash() 生成的盐不同,结果必然不等。
真正容易被忽略的是:加密只发生在写入环节,而修改器本身不参与查询、更新条件构造。一旦你把密码字段加密了,就再也无法用 where('password', $raw) 查用户。这不是 bug,是设计使然。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











