From 5e0a1ce0a1a3b99f35be384d8bebb30e60204d41 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Mon, 10 Aug 2026 15:50:39 +0800 Subject: [PATCH] docs: add mobile-h5 password login API integration design Co-authored-by: Cursor --- ...-10-mobile-h5-password-login-api-design.md | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 docs/superpowers/specs/2026-08-10-mobile-h5-password-login-api-design.md diff --git a/docs/superpowers/specs/2026-08-10-mobile-h5-password-login-api-design.md b/docs/superpowers/specs/2026-08-10-mobile-h5-password-login-api-design.md new file mode 100644 index 00000000..5c686ad5 --- /dev/null +++ b/docs/superpowers/specs/2026-08-10-mobile-h5-password-login-api-design.md @@ -0,0 +1,162 @@ +# mobile-h5 账号密码登录对接真实 API + +> 日期:2026-08-10 +> 适用范围:`mobile-h5` 员工登录页 → 复用 backend Web 登录接口 +> 关联:`docs/superpowers/specs/2026-08-10-miniprogram-login-ui-design.md` +> 后端权威:`backend/app/api/public.py`(`/web/auth/login`、`/web/auth/login-rsa-public-key`) + +--- + +## 1. 目标与范围 + +### 1.1 目标 + +1. 将登录页「账号 + 密码」从 `auth-mock` 改为调用真实后端登录接口。 +2. 传输方式与 `web-admin` 一致:RSA(PKCS#1 v1.5 / JSEncrypt)加密 `{ username, password, ts }`。 +3. 登录成功后持久化会话,进入工作台首页;未登录仍停留登录页。 + +### 1.2 已确认决策 + +| 项 | 约定 | +|----|------| +| 接口 | 复用 `GET /api/web/auth/login-rsa-public-key`、`POST /api/web/auth/login` | +| 加密 | RSA 密文体 `{ encryptedLogin }`,与 web-admin 一致 | +| 配置 | `mobile-h5/utils/config.js` 中可改 `API_BASE_URL`(默认 `http://127.0.0.1:8000/api`) | +| 微信按钮 | 本期置灰不可点;不调微信、不写假登录态 | +| 会话刷新 | 本期存 `refreshToken`,不做自动 refresh / 401 拦截 | +| 后端改动 | **无**(不新增接口、不改登录逻辑) | + +### 1.3 非目标(本期不做) + +- 微信 `code` 换票、openid 绑定、手机号授权 +- Token 自动刷新、全局 401 重登 +- 忘记密码 / 注册 / 记住密码 +- 对称 API 加解密层(登录路径已在 `API_ENCRYPT_EXCLUDE_PATHS`) + +--- + +## 2. 架构 + +``` +┌─────────────────────┐ GET /web/auth/login-rsa-public-key +│ pages/login │ ──► POST /web/auth/login { encryptedLogin } +│ index.vue │ +└─────────┬───────────┘ + │ + ▼ +┌─────────────────────┐ +│ utils/auth.js │ passwordLogin / clearSession / isLoggedIn +│ utils/login-rsa.js │ 拉公钥 + JSEncrypt 加密 +│ utils/request.js │ uni.request 封装(baseURL、解析 code/message/data) +│ utils/config.js │ API_BASE_URL +└─────────┬───────────┘ + │ + ▼ +┌─────────────────────┐ +│ backend │ 校验 sys_user → JWT + userInfo +│ /api/web/auth/* │ +└─────────────────────┘ +``` + +账号含义:`username` = `sys_user.user_no`(与 web-admin 相同)。 + +--- + +## 3. 数据流 + +### 3.1 成功路径 + +1. 前端校验非空(沿用 `validateCredentials`)。 +2. 协议门禁:未勾选则弹 `ConfirmDialog`;取消则中止。 +3. `GET {API_BASE_URL}/web/auth/login-rsa-public-key` → `publicKeyPem`。 +4. 用 JSEncrypt 加密 `JSON.stringify({ username, password, ts: Date.now() })` → `encryptedLogin`。 +5. `POST {API_BASE_URL}/web/auth/login`,body:`{ encryptedLogin }`。 +6. 响应约定:`{ code: 200, message, data: { token, refreshToken, expiresIn, userInfo } }`。 +7. 本地存储(`uni.setStorageSync`): + - `zkxw_mobile_token` ← `data.token` + - `zkxw_mobile_refresh_token` ← `data.refreshToken` + - `zkxw_mobile_user` ← `JSON.stringify(data.userInfo)` +8. Toast「登录成功」→ `uni.reLaunch` 到 `/pages/index/index`。 + +### 3.2 失败路径 + +| 场景 | 表现 | +|------|------| +| 空账号/密码 | 字段级错误(现有逻辑) | +| 网络失败 / 超时 | Toast「网络异常,请稍后重试」 | +| RSA 加密失败 | Toast「登录加密失败,请重试」 | +| `code !== 200`(含 401/403 业务码) | Toast 展示 `message`(如「用户名或密码错误」「账号已被停用…」) | +| 登录中再次点击 | 忽略(`loading` 门禁) | + +### 3.3 已登录进入登录页 + +`onShow`:若本地存在非空 `zkxw_mobile_token`,直接 `reLaunch` 首页(与现逻辑一致;本期不校验 token 是否仍有效)。 + +--- + +## 4. 模块与文件 + +| 文件 | 职责 | +|------|------| +| `mobile-h5/utils/config.js` | 导出 `API_BASE_URL`(默认本地后端) | +| `mobile-h5/utils/request.js` | 薄封装:`get`/`post`;拼接 baseURL;解析统一响应;失败抛带 `message` 的 Error | +| `mobile-h5/utils/login-rsa.js` | 对齐 web-admin `buildWebEncryptedLoginBody`(依赖 `jsencrypt`) | +| `mobile-h5/utils/auth.js` | 由 `auth-mock.js` 演进:保留 session 读写;`passwordLogin` 调真实 API;删除或停用 `mockWechatLogin` | +| `mobile-h5/pages/login/index.vue` | 调 `passwordLogin`;微信按钮加 `is-disabled` / 不绑定点击 | +| `mobile-h5/styles/components/login.scss` | `.login-wechat.is-disabled`:降低透明度、`pointer-events: none` | +| `mobile-h5/package.json` | 增加依赖 `jsencrypt`(与 web-admin 同族) | + +**不修改:** `backend/**`、微信相关 API、协议页内容。 + +### 4.1 依赖说明 + +- 在 `mobile-h5` 安装 `jsencrypt`;小程序构建需能解析该包(HBuilderX / npm 构建按项目既有方式)。 +- 若发行构建对 `jsencrypt` 不友好,允许改为 vendor 拷贝同算法实现,行为须与 web-admin 一致(密文可被现有后端解密)。 + +### 4.2 请求约定 + +- URL:`API_BASE_URL` + 路径(路径以 `/web/auth/...` 开头,**不要**再重复 `/api`)。 +- Header:登录两接口无需 `Authorization`。 +- Content-Type:`application/json`。 +- 超时:建议 15s。 +- 真机调试:开发者工具 / 小程序后台需配置合法 request 域名,或开发期关闭域名校验;`API_BASE_URL` 改为可达地址。 + +--- + +## 5. UI:微信按钮置灰 + +- 模板:`class="login-wechat is-disabled"`,**不**绑定 `@click`(或点击直接 return)。 +- 样式:`opacity: 0.45`(或等价视觉);`pointer-events: none`。 +- 文案仍为「微信授权登录」(表明能力预留,非「即将开通」文案)。 + +协议勾选逻辑对微信按钮本期无意义(不可点);账号密码路径协议门禁保持不变。 + +--- + +## 6. 会话与后续业务请求 + +- 本期仅登录页写会话;首页等业务仍可继续用 mock 数据。 +- `getToken()` / `isLoggedIn()` / `getUser()` / `clearSession()` 保留,供后续页面与登出使用。 +- `clearSession` 须同时清除 token、refreshToken、user。 +- 后续业务 `request` 带 `Authorization: Bearer {token}` 时再扩展,不在本期强制。 + +--- + +## 7. 验收标准 + +1. 使用后台已有启用账号(有角色)可登录成功并进入首页;本地可看到真实 JWT(非 `mock_` 前缀)。 +2. 错误密码 / 停用 / 无角色时,Toast 为后端返回文案。 +3. 微信按钮视觉置灰且无法触发登录。 +4. 修改 `API_BASE_URL` 后请求打到对应主机(可用抓包或后端日志确认)。 +5. 后端代码无变更即可完成联调。 + +--- + +## 8. 风险与备注 + +| 风险 | 缓解 | +|------|------| +| 模拟器 `127.0.0.1` 真机不可达 | 文档说明改 `API_BASE_URL` 为局域网 IP 或测试环境 | +| 时钟偏差导致 RSA `ts` 校验失败 | 与后端 `LOGIN_ENCRYPT_TS_SKEW_SEC` 一致;提示用户校对设备时间 | +| 旧 mock token 残留 | 实现时可用新 key 或登录成功覆盖;建议清除含 `mock_` 前缀的旧会话(可选,启动时一次) | +| 微信登录后续 | 另开设计:openid 绑定或手机号匹配;本期按钮仅占位 |