# 认证模块说明(`src/auth`) ## 1. 目标 - 提供系统管理员创建、院内账号密码登录、B 端小程序手机号登录、C 端小程序手机号登录、`/me` 身份查询。 - 使用 JWT 做认证,院内账号与家属小程序账号走两套守卫。 ## 2. 核心接口 - `POST /auth/system-admin`:创建系统管理员(需引导密钥) - `POST /auth/login`:院内账号密码登录,后台与小程序均可复用 - `POST /auth/login/confirm`:院内账号密码多账号确认登录 - `POST /auth/miniapp/b/phone-login`:B 端小程序手机号登录 - `POST /auth/miniapp/b/phone-login/confirm`:B 端同手机号多账号确认登录 - `POST /auth/miniapp/c/phone-login`:C 端小程序手机号登录 - `GET /auth/me`:返回当前院内登录用户上下文 ## 3. 院内账号密码登录流程 1. 前端提交 `phone + password`,`role` 与 `hospitalId` 都可以选传。 2. 若仅匹配到 1 个院内账号,后端直接返回 JWT。 3. 若匹配到多个院内账号,后端返回 `loginTicket + accounts` 候选列表。 4. 前端带 `loginTicket + userId` 调用确认接口获取最终 JWT。 ## 4. 微信小程序登录流程 ### B 端 1. 前端调用 `wx.login` 获取 `loginCode`。 2. 前端调用手机号授权获取 `phoneCode`。 3. 调用 `POST /auth/miniapp/b/phone-login`。 4. 若手机号仅命中 1 个院内账号,后端直接返回 JWT。 5. 若命中多个院内账号,后端返回 `loginTicket + accounts`。 6. 前端带 `loginTicket + userId` 调用确认接口拿最终 JWT。 ### C 端 1. 前端同样传 `loginCode + phoneCode`。 2. 后端先校验该手机号是否已存在于 `Patient.phone`。 3. 校验通过后创建或绑定 `FamilyMiniAppAccount`,并返回 C 端 JWT。 ## 5. 鉴权流程 ### 院内账号 1. `AccessTokenGuard` 从 `Authorization` 读取 Bearer Token。 2. 校验 JWT 签名、`id`、`iat` 等关键载荷字段。 3. 根据 `id` 回库读取 `User` 当前角色与组织归属。 4. 校验 `iat >= user.tokenValidAfter`,保证旧 token 失效。 ### 家属小程序账号 1. `FamilyAccessTokenGuard` 从 `Authorization` 读取 Bearer Token。 2. 校验 C 端 token 的 `id + type=FAMILY_MINIAPP`。 3. 根据 `id` 回库读取 `FamilyMiniAppAccount`。 4. 将家属账号上下文注入 `request.familyActor`。 ## 6. 环境变量 - `AUTH_TOKEN_SECRET` - `SYSTEM_ADMIN_BOOTSTRAP_KEY` - `WECHAT_MINIAPP_APPID` - `WECHAT_MINIAPP_SECRET` ## 7. 关键规则 - 后台 Web 与 B 端小程序都可以复用 `POST /auth/login` 做账号密码登录。 - 密码登录命中多个院内账号时,不再强制前端手填 `hospitalId`,改为后端返回候选账号供选择。 - B 端小程序登录复用 `User` 表,继续使用 `openId`。 - B 端账号未绑定 `openId` 时,首次小程序登录自动绑定。 - 同一个 `openId` 可绑定多个院内账号,支持同一微信号切换多角色/多院区账号。 - 若目标院内账号已绑定其他微信号,仍需先在用户管理中清空该账号的 `openId` 再重新绑定。 - C 端家属账号独立存放在 `FamilyMiniAppAccount`。 - C 端手机号必须先存在于患者档案,否则拒绝登录。 - `serviceUid` 仅预留字段,本次不提供绑定接口。