必须用 hash::check() 验证当前密码,不能用 rule::exists();应封装为自定义规则 currentpassword,passes() 中先判 auth::user() 是否存在,再校验哈希,需覆盖未登录、空值、密码字段异常等边界场景。

验证当前密码是否正确:用 Rule::exists() 不行,得自己写
直接用 exists 规则查密码字段是错的——数据库里存的是哈希值,而用户提交的是明文,exists 只做字符串匹配,永远不成立。必须在规则里手动调用 Hash::check() 做比对。
推荐封装成自定义验证规则对象,而不是闭包或内联逻辑,便于复用和测试。
创建自定义规则类:CurrentPassword
运行命令生成规则类:
php artisan make:rule CurrentPassword
编辑生成的 app/Rules/CurrentPassword.php,关键点:
-
passes()方法里先取当前登录用户(Auth::user()),再用Hash::check($value, $user->password) - 务必检查
$user是否存在,避免未登录时调用->password报Trying to get property 'password' of non-object - 不要在
validate()或构造函数里查库,延迟到passes()执行更安全
在 Form Request 中使用 CurrentPassword 规则
比如修改密码表单的验证逻辑:
public function rules()
{
return [
'current_password' => ['required', new CurrentPassword],
'password' => ['required', 'confirmed', 'min:8'],
];
}
注意:current_password 字段名要和前端传入一致;如果字段名是 old_password,规则里也要同步改参数名,否则 $value 拿不到值。
另外,该规则默认只对已认证用户生效。若控制器中用了 auth:api 中间件,但请求没带 token,Auth::user() 为 null,规则会直接返回 false —— 这是预期行为,不用额外抛异常。
测试时容易漏掉的边界情况
写单元测试时重点覆盖这些场景:
- 用户未登录 →
Auth::user()为 null,规则应返回false - 输入空字符串或 null →
$value为空,Hash::check()返回false,但最好在规则开头加if (empty($value)) return false; - 密码哈希格式异常(如字段被意外清空为
"")→Hash::check()会静默失败,建议加if (! $user->password || ! Hash::needsRehash($user->password))提前拦截
真实项目里,用户模型的 password 字段极少为空,但数据库迁移出错或种子数据异常时可能触发,不处理会导致“输什么都提示密码错误”且无日志可查。











