日期: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)
auth-mock 改为调用真实后端登录接口。web-admin 一致:RSA(PKCS#1 v1.5 / JSEncrypt)加密 { username, password, ts }。| 项 | 约定 |
|---|---|
| 接口 | 复用 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 拦截 |
| 后端改动 | 无(不新增接口、不改登录逻辑) |
code 换票、openid 绑定、手机号授权API_ENCRYPT_EXCLUDE_PATHS)┌─────────────────────┐ 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 相同)。
validateCredentials)。ConfirmDialog;取消则中止。GET {API_BASE_URL}/web/auth/login-rsa-public-key → publicKeyPem。JSON.stringify({ username, password, ts: Date.now() }) → encryptedLogin。POST {API_BASE_URL}/web/auth/login,body:{ encryptedLogin }。{ code: 200, message, data: { token, refreshToken, expiresIn, userInfo } }。uni.setStorageSync):
zkxw_mobile_token ← data.tokenzkxw_mobile_refresh_token ← data.refreshTokenzkxw_mobile_user ← JSON.stringify(data.userInfo)uni.reLaunch 到 /pages/index/index。| 场景 | 表现 |
|---|---|
| 空账号/密码 | 字段级错误(现有逻辑) |
| 网络失败 / 超时 | Toast「网络异常,请稍后重试」 |
| RSA 加密失败 | Toast「登录加密失败,请重试」 |
code !== 200(含 401/403 业务码) |
Toast 展示 message(如「用户名或密码错误」「账号已被停用…」) |
| 登录中再次点击 | 忽略(loading 门禁) |
onShow:若本地存在非空 zkxw_mobile_token,直接 reLaunch 首页(与现逻辑一致;本期不校验 token 是否仍有效)。
| 文件 | 职责 |
|---|---|
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、协议页内容。
mobile-h5 安装 jsencrypt;小程序构建需能解析该包(HBuilderX / npm 构建按项目既有方式)。jsencrypt 不友好,允许改为 vendor 拷贝同算法实现,行为须与 web-admin 一致(密文可被现有后端解密)。API_BASE_URL + 路径(路径以 /web/auth/... 开头,不要再重复 /api)。Authorization。application/json。API_BASE_URL 改为可达地址。class="login-wechat is-disabled",不绑定 @click(或点击直接 return)。opacity: 0.45(或等价视觉);pointer-events: none。协议勾选逻辑对微信按钮本期无意义(不可点);账号密码路径协议门禁保持不变。
getToken() / isLoggedIn() / getUser() / clearSession() 保留,供后续页面与登出使用。clearSession 须同时清除 token、refreshToken、user。request 带 Authorization: Bearer {token} 时再扩展,不在本期强制。mock_ 前缀)。API_BASE_URL 后请求打到对应主机(可用抓包或后端日志确认)。| 风险 | 缓解 |
|---|---|
模拟器 127.0.0.1 真机不可达 |
文档说明改 API_BASE_URL 为局域网 IP 或测试环境 |
时钟偏差导致 RSA ts 校验失败 |
与后端 LOGIN_ENCRYPT_TS_SKEW_SEC 一致;提示用户校对设备时间 |
| 旧 mock token 残留 | 实现时可用新 key 或登录成功覆盖;建议清除含 mock_ 前缀的旧会话(可选,启动时一次) |
| 微信登录后续 | 另开设计:openid 绑定或手机号匹配;本期按钮仅占位 |