- 新增字典删除接口 `/api/dictionary/delete` - 新增字典详情接口 `/api/dictionary/detail` - 新增字典列表接口 `/api/dictionary/list` - 新增字典更新接口 `/api/dictionary/update` - 新增字典服务 `dictionaryService.js`,实现字典的创建、更新、删除和查询功能 - 新增字典管理页面 `dictionary-manage.js`,支持字典的增删改查操作 - 新增管理主页 `index.js`,提供字典管理入口 - 新增示例页面 `page-b.js`,用于验证页面跳转
9.4 KiB
9.4 KiB
OpenSpec 变更记录:PocketBase Hooks 认证链路加固
日期
- 2026-03-23
范围
本次变更覆盖 pocket-base/ 下 PocketBase hooks 项目的微信登录、平台注册/登录、资料更新、token 刷新、认证落库、错误可观测性、索引策略、字典管理、页面辅助操作、健康检查版本探针、OpenAPI 鉴权与统一响应规范。
一、认证模型调整
1. 认证体系
- 保持 PocketBase 原生 auth token 作为唯一正式认证令牌。
- 登录与刷新响应统一为项目标准结构:
code、msg、data,认证成功时额外返回顶层token。 authMethod统一使用空字符串'',避免触发不必要的 MFA / login alerts 校验。
2. Header 规则
- 正式认证 Header 为:
Authorization: Bearer <token> - 非标准 Header
Open-Authorization不属于本项目接口定义。 users_wx_openidHeader 已从 active hooks 鉴权链路移除。
二、身份字段与数据模型约束
1. openid 作为唯一业务身份锚点
tbl_auth_users统一保留openid作为全平台身份锚点。- 微信用户:
openid = 微信 openid - 平台用户:
openid = 服务端生成的 GUID - 业务逻辑中不再使用
users_wx_openid。 - 用户查询、token 刷新、资料更新均基于 auth record 的
openid。
2. auth 集合兼容字段
由于 tbl_auth_users 当前为 PocketBase auth 集合,登录注册时为兼容 PocketBase 原生 auth 校验,新增以下兼容策略:
email使用占位格式:- 微信用户:
<openid>@wechat.local - 平台用户:
<openid>@manage.local
- 微信用户:
- 自动生成随机密码
- 自动补齐
passwordConfirm
说明:
- 占位
email仅用于满足 auth 集合保存条件,不代表用户真实邮箱。 - 业务主身份仍然是
openid。
3. 自定义字段可空策略
tbl_auth_users的自定义字段目标约束为:除openid外,其余业务字段均允许为空。- 已将 schema 脚本中的
user_id改为非必填。 - 其余业务字段保持非必填。
三、查询与排序修复
1. 移除无意义的 created 排序
在 hooks 查询中,以下查询原先使用 '-created' 排序:
- 按
openid查询用户 - 按
company_id查询公司 - 按
users_phone查询重复手机号
该写法在 PocketBase 当前运行场景下触发:
invalid sort field "created"
现已统一移除排序参数,改为空排序字符串,因为这些查询本质上均为精确匹配或去重检查,不依赖排序。
四、错误可观测性增强
1. 登录路由显式错误响应
POST /api/wechat/login 新增局部 try/catch:
- 保留业务状态码
- 返回
{ code, msg, data } - 写入
logger.error('微信登录失败', ...)
2. 全局错误包装顺序修正
routerUse(...)全局错误包装提前到路由注册前。- 统一兼容
err.statusCode/err.status。
3. auth 保存失败透传
新增 saveAuthUserRecord(record) 包装 $app.save(record):
- 失败时统一抛出
保存认证用户失败 - 附带
originalMessage与originalData
目的:
- 避免 PocketBase 默认
Something went wrong while processing your request.吞掉具体原因。
五、数据库索引策略修复
1. users_phone 索引调整
原设计:
users_phone唯一索引
问题:
- 新用户注册阶段手机号为空,多个空值会触发唯一约束冲突,导致注册失败。
现调整为:
users_phone普通索引
说明:
- 手机号唯一性改由业务逻辑在资料完善阶段校验。
- 允许多个未完善资料用户以空手机号存在。
六、接口契约同步结果
当前 active PocketBase hooks 契约如下:
POST /api/system/test-helloworldPOST /api/system/healthPOST /api/system/refresh-tokenPOST /api/platform/registerPOST /api/platform/loginPOST /api/wechat/loginPOST /api/wechat/profilePOST /api/dictionary/listPOST /api/dictionary/detailPOST /api/dictionary/createPOST /api/dictionary/updatePOST /api/dictionary/delete
其中平台用户链路补充为:
POST /api/platform/register
- body 必填:
users_name、users_phone、password、passwordConfirm、users_picture - 自动生成 GUID 并写入统一身份字段
openid - 写入
users_idtype = ManagePlatform - 成功时返回统一结构:
code、msg、data,并在顶层额外返回token
POST /api/platform/login
- body 必填:
login_account、password - 仅允许
users_idtype = ManagePlatform - 前端使用邮箱或手机号 + 密码提交
- 服务端先通过 PocketBase
auth-with-password校验身份,再由当前 hooks 进程签发正式 token - 成功时返回统一结构:
code、msg、data,并在顶层额外返回token
其中:
POST /api/wechat/login
- body 必填:
users_wx_code - 自动以微信 code 换取微信侧
openid并写入统一身份字段 - 若不存在 auth 用户则尝试创建
tbl_auth_users记录 - 写入
users_idtype = WeChat - 成功时返回统一结构:
code、msg、data,并在顶层额外返回token
POST /api/wechat/profile
- 需
Authorization - 基于当前 auth record 的
openid定位用户 - 服务端用
users_phone_code换取手机号后保存
POST /api/system/refresh-token
- body 可选:
users_wx_code(允许为空) Authorization可选:- 若 token 仍有效:基于当前 auth record 续签
- 若 token 已过期:回退到微信 code 重签流程
- 若 token 已过期且未提供
users_wx_code,返回:token已过期,请上传users_wx_code - 返回统一结构:
code、msg、data,并在顶层额外返回新token - 属于系统级通用认证能力,不限定为微信专属接口
字典管理接口
新增 dictionary 分类接口,统一要求平台管理用户访问:
POST /api/dictionary/list- 支持按
dict_name模糊搜索 - 返回字典全量信息,并将
dict_word_enum、dict_word_description、dict_word_sort_order组装为items
- 支持按
POST /api/dictionary/detail- 按
dict_name查询单条字典
- 按
POST /api/dictionary/create- 新增字典,
system_dict_id自动生成,dict_name唯一
- 新增字典,
POST /api/dictionary/update- 按
original_dict_name/dict_name更新字典
- 按
POST /api/dictionary/delete- 按
dict_name真删除字典
- 按
说明:
dict_word_enum、dict_word_description、dict_word_sort_order已统一改为 JSON 字符串持久化,其中dict_word_sort_order已改为text类型。- 查询时统一聚合为:
items: [{ enum, description, sortOrder }]
七、页面与运维辅助能力新增
1. PocketBase 页面
新增页面:
/web/web/dictionary-manage
页面能力:
- 首页支持跳转到子页面
- 字典管理页支持:
- Bearer Token 粘贴与本地保存
dict_name模糊搜索- 指定字典查询
- 行内编辑基础字段
- 弹窗编辑枚举项
- 新增 / 删除字典
- 返回主页
2. 健康检查版本探针
POST /api/system/health 新增:
data.version
用途:
- 通过修改
APP_VERSION判断 hooks 是否已成功部署并生效
配置来源:
- 进程环境变量
APP_VERSION - 或
runtime.js
八、OpenAPI 与 Apifox 调试策略调整
1. 统一返回结构
所有对外接口统一返回:
codemsgdata
认证成功类接口额外返回:
token
不再返回以下顶层字段:
recordmeta
2. 鉴权文档策略
OpenAPI 文档中已取消 bearerAuth 鉴权组件与接口级重复 Authorization 参数。
统一约定:
- 在 Apifox 环境中配置全局 Header:
Authorization: Bearer {{token}} - 不再依赖文档中的 Bearer 组件自动注入
此举目的是:
- 避免接口页重复出现局部
Authorization - 统一依赖环境变量完成鉴权注入
九、当前已知边界
tbl_auth_users为 PocketBaseauth集合,因此仍受 PocketBase auth 内置规则影响。- 自定义字段“除 openid 外均可空”已在脚本层按目标放宽,但 auth 集合结构更新仍可能触发 PocketBase 服务端限制。
- 若线上仍返回 PocketBase 默认 400,需要确保最新 hooks 已部署并重启生效。
- 平台登录通过回源 PocketBase REST 完成密码校验,因此
POCKETBASE_API_URL必须配置为 PocketBase 进程/容器内部可达地址,不应使用外部 HTTPS 域名。 - Apifox 环境中需自行维护全局 Header:
Authorization: Bearer {{token}},否则鉴权接口不会自动携带 token。
十、归档建议
部署时至少同步以下文件:
pocket-base/bai-api-main.pb.jspocket-base/bai-web-main.pb.jspocket-base/bai_api_pb_hooks/pocket-base/bai_web_pb_hooks/pocket-base/spec/openapi.yamlscript/pocketbase.js
并在 PocketBase 环境中执行 schema 同步后重启服务,再进行接口验证。
建议归档后的发布核验顺序:
POST /api/system/health:确认data.versionPOST /api/platform/login:确认返回统一结构与顶层tokenPOST /api/dictionary/list:确认鉴权与字典接口可用
十一、归档状态
- 已将本轮字典管理、PocketBase 页面、统一响应、平台登录兼容修复、健康检查版本探针、OpenAPI/Apifox 鉴权策略调整并入本变更记录。
- 本记录可作为当前 PocketBase hooks 阶段性归档基线继续维护。