登录支持用户名,登录页展示用户名而非手机号 #2

Closed
opened 2026-11-01 03:05:52 +00:00 by laoyang · 1 comment
Owner

需求

不要放手机号了,还是用用户名吧。看一下用用户名能不能登录?能用就直接放用户名。

现状(已实测,不是推断)

Auth::attempt() 只按 phone_hash 查:

$phoneHash = hash('sha256', $phone);
'SELECT * FROM users WHERE phone_hash = ? AND role IN ("admin","user") AND status = "active" LIMIT 1'

线上实测:

输入 结果
laoyang + 12345678 ❌ 302 弹回登录页,登录失败
13361281915 + 12345678 ✅ 200 进入首页

⇒ 用户名登录不支持。想让登录页展示用户名,必须先改代码。

与「不改代码」的冲突(已向用户确认)

用户先前要求「这个改动不要提交到代码库」。但支持用户名登录属于功能改动,
必须改 src/Auth.php + AuthController + 模板,无法只存在于线上。
已与用户确认,选择走正规流程入仓库。

改法

  1. Auth::attempt():先按 phone_hash 查;查不到再按 name 查
    (family_id 范围内、role in (admin,user)、status=active)。
  2. 名字可能重名 → 命中多条时视为失败并提示,不做「取第一条」这种静默猜测。
  3. 登录表单 label 与 placeholder 改成「手机号 / 用户名」。
  4. 错误文案从「手机号或密码错误」改成「账号或密码错误」。

验收

  • laoyang / 12345678 能登录 → 200
  • 13361281915 / 12345678 仍能登录 → 200(不能破坏原路径)
  • 错误密码两条路径都失败
  • 重名用户不会误登进别人账号
  • 登录页提示文案改为用户名
## 需求 > 不要放手机号了,还是用用户名吧。看一下用用户名能不能登录?能用就直接放用户名。 ## 现状(已实测,不是推断) `Auth::attempt()` 只按 `phone_hash` 查: ```php $phoneHash = hash('sha256', $phone); 'SELECT * FROM users WHERE phone_hash = ? AND role IN ("admin","user") AND status = "active" LIMIT 1' ``` 线上实测: | 输入 | 结果 | |---|---| | `laoyang` + `12345678` | ❌ 302 弹回登录页,登录失败 | | `13361281915` + `12345678` | ✅ 200 进入首页 | ⇒ **用户名登录不支持**。想让登录页展示用户名,必须先改代码。 ## 与「不改代码」的冲突(已向用户确认) 用户先前要求「这个改动不要提交到代码库」。但支持用户名登录属于功能改动, 必须改 `src/Auth.php` + `AuthController` + 模板,无法只存在于线上。 已与用户确认,选择走正规流程入仓库。 ## 改法 1. `Auth::attempt()`:先按 `phone_hash` 查;查不到再按 `name` 查 (`family_id` 范围内、`role in (admin,user)`、`status=active`)。 2. 名字可能重名 → 命中多条时**视为失败**并提示,不做「取第一条」这种静默猜测。 3. 登录表单 label 与 placeholder 改成「手机号 / 用户名」。 4. 错误文案从「手机号或密码错误」改成「账号或密码错误」。 ## 验收 - `laoyang` / `12345678` 能登录 → 200 - `13361281915` / `12345678` 仍能登录 → 200(不能破坏原路径) - 错误密码两条路径都失败 - 重名用户不会误登进别人账号 - 登录页提示文案改为用户名
Author
Owner

验收记录

改了什么

文件 改动
src/Auth.php attempt() 先按 phone_hash 精确查,未命中再按 name 查;重名命中多条一律 return null
src/Controllers/AuthController.php 错误文案「手机号或密码错误」→「账号或密码错误」
templates/auth/login.php label「手机号」→「手机号 / 用户名」,placeholder 同步

怎么验的

逻辑单测 10/10(Auth::attempt 直调,不经 HTTP):

  • 手机号 13361281915 + 正确密码 → 登录成功,name=laoyang
  • 姓名 laoyang + 正确密码 → 登录成功,id=1(与手机号同一账号)
  • 手机号 / 姓名 + 错误密码 → 双路径均拒绝
  • 不存在的名字、空账号、空密码 → 均拒绝
  • 临时插入同名用户后 → 拒绝登录(关键安全项);清理后恢复正常

反向验证:把 count($rows) !== 1 改成 count($rows) < 1(= 取第一条),
断言立刻变红并报出「误登进 id=1」;恢复后回绿。

端到端(线上 HTTP):

  • 用户名登录 → 首页 200
  • 手机号登录 → 首页 200(回归未坏)
  • 错误密码 → 302 弹回登录页

部署

  • 提交 d6a7cc9,已推送 fdc890f..d6a7cc9
  • 线上三个文件已更新,审计日志已记
  • 登录页演示提示改为「用户名 laoyang / 密码 12345678」

遗留

登录页的「演示站点」提示块只在线上、不入库(用户明确要求)。
⇒ 下次部署 templates/auth/login.php 会把它冲掉,需要重打。
建议后续做成部署后置钩子,但属于另一件事。

## 验收记录 ### 改了什么 | 文件 | 改动 | |---|---| | `src/Auth.php` | `attempt()` 先按 `phone_hash` 精确查,未命中再按 `name` 查;**重名命中多条一律 `return null`** | | `src/Controllers/AuthController.php` | 错误文案「手机号或密码错误」→「账号或密码错误」 | | `templates/auth/login.php` | label「手机号」→「手机号 / 用户名」,placeholder 同步 | ### 怎么验的 **逻辑单测 10/10**(`Auth::attempt` 直调,不经 HTTP): - 手机号 `13361281915` + 正确密码 → 登录成功,name=laoyang - 姓名 `laoyang` + 正确密码 → 登录成功,id=1(与手机号同一账号) - 手机号 / 姓名 + 错误密码 → 双路径均拒绝 - 不存在的名字、空账号、空密码 → 均拒绝 - **临时插入同名用户后 → 拒绝登录**(关键安全项);清理后恢复正常 **反向验证**:把 `count($rows) !== 1` 改成 `count($rows) < 1`(= 取第一条), 断言立刻变红并报出「误登进 id=1」;恢复后回绿。 **端到端(线上 HTTP)**: - 用户名登录 → 首页 200 - 手机号登录 → 首页 200(回归未坏) - 错误密码 → 302 弹回登录页 ### 部署 - 提交 `d6a7cc9`,已推送 `fdc890f..d6a7cc9` - 线上三个文件已更新,审计日志已记 - 登录页演示提示改为「用户名 laoyang / 密码 12345678」 ### 遗留 登录页的「演示站点」提示块**只在线上、不入库**(用户明确要求)。 ⇒ 下次部署 `templates/auth/login.php` 会把它冲掉,需要重打。 建议后续做成部署后置钩子,但属于另一件事。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: laoyang/TripLog#2