From d6a7cc99bcf650d324977f66f3577ec876cf551c Mon Sep 17 00:00:00 2001 From: laoyang Date: Sun, 1 Nov 2026 11:07:30 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BB=E5=BD=95=E6=94=AF=E6=8C=81=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=90=8D=EF=BC=8C=E4=B8=8E=E6=89=8B=E6=9C=BA=E5=8F=B7?= =?UTF-8?q?=E5=B9=B6=E5=AD=98=20(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原来 Auth::attempt 只按 phone_hash 查,用户名永远登不进去。 家人账号常常不填手机号,演示场景下用名字登录更自然。 - 先按手机号 hash 精确查(唯一),未命中再按 name 查 - 重名命中多条一律拒绝,绝不取第一条(否则 A 的密码能登进 B 的账号) - 表单 label 改「手机号 / 用户名」,错误文案改「账号或密码错误」 验证:逻辑单测 10/10(含重名拒绝);反向验证改坏判断即变红 (#2) --- src/Auth.php | 39 ++++++++++++++++++++++++------ src/Controllers/AuthController.php | 2 +- templates/auth/login.php | 4 +-- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/Auth.php b/src/Auth.php index dc5c987..765e46e 100644 --- a/src/Auth.php +++ b/src/Auth.php @@ -60,21 +60,44 @@ class Auth } /** - * 通过手机号 + 密码尝试登录 + * 尝试登录。账号可以是**手机号**,也可以是**姓名**。 + * + * 为什么两种都收:安装向导创建的管理员填的是手机号,而家人账号常常不填手机号 + * (只有名字),演示/内网场景下用名字登录更自然。 + * + * 顺序:先按手机号 hash 精确匹配(唯一,不会歧义),再按姓名匹配。 + * 姓名可能重名 ⇒ **命中多条一律判失败**,绝不「取第一条」—— + * 那等于让 A 用密码登进了 B 的账号,是最坏的一种 bug。 + * * @return array|null 成功返回用户数组,失败返回 null */ - public static function attempt(string $phone, string $password): ?array + public static function attempt(string $account, string $password): ?array { - $phone = trim($phone); - if ($phone === '' || $password === '') return null; + $account = trim($account); + if ($account === '' || $password === '') return null; - $phoneHash = hash('sha256', $phone); - $stmt = Database::get()->prepare( + $db = Database::get(); + + // ① 手机号:走 sha256 精确查(唯一,不会歧义) + $stmt = $db->prepare( 'SELECT * FROM users WHERE phone_hash = ? AND role IN ("admin","user") AND status = "active" LIMIT 1' ); - $stmt->execute([$phoneHash]); + $stmt->execute([hash('sha256', $account)]); $user = $stmt->fetch(); - if (!$user) return null; + + // ② 手机号没命中,再按姓名查 + if (!$user) { + $stmt = $db->prepare( + 'SELECT * FROM users WHERE name = ? AND role IN ("admin","user") AND status = "active"' + ); + $stmt->execute([$account]); + $rows = $stmt->fetchAll(); + + // 重名 → 拒绝,不做猜测 + if (count($rows) !== 1) return null; + $user = $rows[0]; + } + if (!password_verify($password, (string)($user['password_hash'] ?? ''))) return null; return $user; diff --git a/src/Controllers/AuthController.php b/src/Controllers/AuthController.php index 4a3bdcb..d51b1e5 100644 --- a/src/Controllers/AuthController.php +++ b/src/Controllers/AuthController.php @@ -24,7 +24,7 @@ class AuthController $user = Auth::attempt($phone, $password); if (!$user) { - flash('error', '手机号或密码错误'); + flash('error', '账号或密码错误'); redirect('auth/login'); } diff --git a/templates/auth/login.php b/templates/auth/login.php index d4e567c..58cf0d0 100644 --- a/templates/auth/login.php +++ b/templates/auth/login.php @@ -5,8 +5,8 @@
请登录后继续