docs: add mobile-h5 password login API integration design
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
ef259f1f0c
commit
5e0a1ce0a1
1 file changed
+162
@@ -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 绑定或手机号匹配;本期按钮仅占位 |
|
||||
Reference in new issue
Block a user