feat: 增强 PocketBase hooks 认证功能

- 更新微信登录、平台注册/登录、资料更新、token 刷新、认证落库等功能,统一使用 openid 作为全平台身份锚点。
- 新增平台用户注册和登录接口,支持手机号和密码认证。
- 实现系统级 token 刷新接口,支持通过微信 code 重新签发 token。
- 新增用户总数查询接口,返回 tbl_auth_users 表中的用户总数。
- 更新 OpenAPI 文档,反映新的接口和数据结构。
- 修改数据库结构,调整字段名称和索引。
- 新增页面示例,展示基本的 HTML 页面结构。
This commit is contained in:
2026-03-25 20:03:46 +08:00
parent 02d5686c7b
commit 6490fc427f
20 changed files with 971 additions and 90 deletions

View File

@@ -6,7 +6,7 @@
## 范围
本次变更覆盖 `pocket-base/` 下 PocketBase hooks 项目的微信登录、资料更新、token 刷新、认证落库、错误可观测性、索引策略与运行规范。
本次变更覆盖 `pocket-base/` 下 PocketBase hooks 项目的微信登录、平台注册/登录、资料更新、token 刷新、认证落库、错误可观测性、索引策略与运行规范。
---
@@ -30,7 +30,9 @@
### 1. openid 作为唯一业务身份锚点
- `tbl_auth_users` 保留 `openid` 作为微信身份锚点。
- `tbl_auth_users` 统一保留 `openid` 作为全平台身份锚点。
- 微信用户:`openid = 微信 openid`
- 平台用户:`openid = 服务端生成的 GUID`
- 业务逻辑中不再使用 `users_wx_openid`
- 用户查询、token 刷新、资料更新均基于 auth record 的 `openid`
@@ -38,7 +40,9 @@
由于 `tbl_auth_users` 当前为 PocketBase `auth` 集合,登录注册时为兼容 PocketBase 原生 auth 校验,新增以下兼容策略:
- `email` 使用占位格式:`<openid>@wechat.local`
- `email` 使用占位格式:
- 微信用户:`<openid>@wechat.local`
- 平台用户:`<openid>@manage.local`
- 自动生成随机密码
- 自动补齐 `passwordConfirm`
@@ -92,7 +96,7 @@
新增 `saveAuthUserRecord(record)` 包装 `$app.save(record)`
- 失败时统一抛出 `保存微信用户失败`
- 失败时统一抛出 `保存认证用户失败`
- 附带 `originalMessage``originalData`
目的:
@@ -130,17 +134,36 @@
- `POST /api/system/test-helloworld`
- `POST /api/system/health`
- `POST /api/system/refresh-token`
- `POST /api/platform/register`
- `POST /api/platform/login`
- `POST /api/wechat/login`
- `POST /api/wechat/profile`
- `POST /api/wechat/refresh-token`
其中平台用户链路补充为:
### `POST /api/platform/register`
- body 必填:`users_name``users_phone``password``passwordConfirm``users_picture`
- 自动生成 GUID 并写入统一身份字段 `openid`
- 写入 `users_idtype = ManagePlatform`
- 成功时返回 PocketBase 原生 token + auth record + meta
### `POST /api/platform/login`
- body 必填:`users_phone``password`
- 仅允许 `users_idtype = ManagePlatform`
- 前端使用手机号+密码提交
- 服务端内部仍通过 PocketBase 原生 password auth 返回原生 token
其中:
### `POST /api/wechat/login`
- body 必填:`users_wx_code`
- 自动以微信 code 换取 `openid`
- 自动以微信 code 换取微信侧 `openid` 并写入统一身份字段
- 若不存在 auth 用户则尝试创建 `tbl_auth_users` 记录
- 写入 `users_idtype = WeChat`
- 成功时返回 PocketBase 原生 token + auth record + meta
### `POST /api/wechat/profile`
@@ -149,10 +172,15 @@
- 基于当前 auth record 的 `openid` 定位用户
- 服务端用 `users_phone_code` 换取手机号后保存
### `POST /api/wechat/refresh-token`
### `POST /api/system/refresh-token`
- `Authorization`
- 直接基于当前 auth record 返回新的 PocketBase 原生 token
- body 可选:`users_wx_code`(允许为空)
- `Authorization` 可选:
- 若 token 仍有效:基于当前 auth record 续签
- 若 token 已过期:回退到微信 code 重签流程
- 若 token 已过期且未提供 `users_wx_code`,返回:`token已过期请上传users_wx_code`
- 返回精简结构,仅返回新 token不返回完整登录用户信息
- 属于系统级通用认证能力,不限定为微信专属接口
---

View File

@@ -1,7 +1,11 @@
openapi: 3.1.0
info:
title: BAI PocketBase Hooks API
description: 基于 PocketBase `bai_api_pb_hooks` 的对外接口文档,可直接导入 Postman。
description: |
基于 PocketBase `bai_api_pb_hooks` 的对外接口文档,可直接导入 Postman。
当前 `tbl_auth_users.openid` 已被定义为全平台统一身份锚点:
- 微信用户:`openid = 微信 openid`
- 平台用户:`openid = 服务端生成的 GUID`
version: 1.0.0
servers:
- url: https://bai-api.blv-oa.com/pb
@@ -12,7 +16,9 @@ tags:
- name: 系统
description: 基础检查接口
- name: 微信认证
description: 基于微信 openid 与 PocketBase 原生 token 的认证接口
description: 面向微信用户的认证接口;认证成功后仍统一使用全平台 `openid` 与 PocketBase 原生 token
- name: 平台认证
description: 面向平台用户的认证接口;平台用户会生成 GUID 并写入统一 `openid` 字段。
components:
securitySchemes:
bearerAuth:
@@ -42,6 +48,13 @@ components:
timestamp:
type: string
format: date-time
UsersCountData:
type: object
properties:
total_users:
type: integer
description: tbl_auth_users 表中的用户总数
example: 128
HelloWorldData:
type: object
properties:
@@ -64,11 +77,28 @@ components:
additionalProperties: true
UserInfo:
type: object
description: |
统一用户视图。
其中 `openid` 为全平台统一身份标识:微信用户使用微信 openid平台用户使用服务端生成 GUID。
properties:
pb_id:
type: string
users_convers_id:
type: string
users_id:
type: string
users_idtype:
type: string
description: 用户身份来源类型
enum: [WeChat, ManagePlatform]
users_id_number:
type: string
users_status:
type: number
users_rank_level:
type: number
users_auth_type:
type: number
users_type:
type: string
enum: [游客, 注册用户]
@@ -78,12 +108,21 @@ components:
type: string
users_phone_masked:
type: string
users_level:
type: string
users_picture:
type: string
openid:
type: string
description: 全平台统一身份标识;微信用户为微信 openid平台用户为服务端生成的 GUID
company_id:
type: string
users_parent_id:
type: string
users_promo_code:
type: string
usergroups_id:
type: string
company:
$ref: '#/components/schemas/CompanyInfo'
created:
@@ -92,6 +131,9 @@ components:
type: string
PocketBaseAuthResponse:
type: object
description: |
PocketBase 原生认证响应。
客户端可直接使用返回的 `token` 与 PocketBase SDK 或当前 hooks 接口交互。
properties:
token:
type: string
@@ -121,6 +163,7 @@ components:
WechatLoginRequest:
type: object
required: [users_wx_code]
description: 微信小程序登录/注册请求体。
properties:
users_wx_code:
type: string
@@ -129,6 +172,7 @@ components:
WechatProfileRequest:
type: object
required: [users_name, users_phone_code, users_picture]
description: 微信用户资料完善请求体。
properties:
users_name:
type: string
@@ -147,6 +191,70 @@ components:
enum: [update_success]
user:
$ref: '#/components/schemas/UserInfo'
PlatformRegisterRequest:
type: object
required: [users_name, users_phone, password, passwordConfirm, users_picture]
description: 平台用户注册请求体;注册成功后将生成 GUID 并写入统一 `openid` 字段。
properties:
users_name:
type: string
example: 张三
users_phone:
type: string
example: 13800138000
password:
type: string
example: 12345678
passwordConfirm:
type: string
example: 12345678
users_picture:
type: string
example: https://example.com/avatar.png
users_id_number:
type: string
users_level:
type: string
users_type:
type: string
company_id:
type: string
users_parent_id:
type: string
users_promo_code:
type: string
usergroups_id:
type: string
PlatformLoginRequest:
type: object
required: [users_phone, password]
description: 平台用户登录请求体;前端使用手机号+密码提交,服务端内部转换为 PocketBase 原生 password auth。
properties:
users_phone:
type: string
example: 13800138000
password:
type: string
example: 12345678
SystemRefreshTokenRequest:
type: object
description: |
系统刷新 token 请求体。
`users_wx_code` 允许为空。
当 `Authorization` 对应 token 有效时,可不传或传空;
当 token 失效时,需提供 `users_wx_code` 走微信 code 重新签发流程。
properties:
users_wx_code:
type: string
nullable: true
description: 微信小程序登录临时凭证 code
example: 0a1b2c3d4e5f6g
RefreshTokenData:
type: object
properties:
token:
type: string
description: 新签发的 PocketBase 原生 auth token
paths:
/api/system/test-helloworld:
post:
@@ -180,13 +288,76 @@ paths:
properties:
data:
$ref: '#/components/schemas/HealthData'
/api/system/users-count:
post:
tags: [系统]
summary: 查询用户总数
description: 统计 `tbl_auth_users` 集合中的记录总数,并返回一个数值。
responses:
'200':
description: 成功
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/ApiResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/UsersCountData'
/api/system/refresh-token:
post:
tags: [系统]
summary: 刷新系统认证 token
description: |
当前实现支持两种刷新路径:
1) 若 `Authorization` 对应 token 仍有效:直接按当前 auth record 续签(不调用微信接口)。
2) 若 token 已过期:仅在 body 提供 `users_wx_code` 时才走微信 code 重新签发。
返回体仅包含新的 `token`,不返回完整登录用户信息。
parameters:
- in: header
name: Authorization
required: false
schema:
type: string
description: 可选。建议传入旧 token`Bearer <token>`)以优先走有效 token 续签路径。
requestBody:
required: false
content:
application/json:
schema:
$ref: '#/components/schemas/SystemRefreshTokenRequest'
responses:
'200':
description: 刷新成功(返回精简 token
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/ApiResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/RefreshTokenData'
'400':
description: 参数错误或微信侧身份换取失败
'401':
description: token 无效/已过期,且未提供 users_wx_code
'404':
description: 用户不存在
'415':
description: 请求体必须为 application/json
'429':
description: 重复请求过于频繁
/api/wechat/login:
post:
tags: [微信认证]
summary: 微信登录/注册合一
description: |
使用微信 code 换取 openid。
使用微信 code 换取微信侧 openid,并写入统一身份字段 `tbl_auth_users.openid`
若 `tbl_auth_users` 中不存在对应用户则自动创建 auth record随后返回 PocketBase 原生 auth token。
首次注册创建时会写入 `users_idtype = WeChat`。
返回的 `token` 可直接用于 PocketBase SDK 与当前 hooks 接口调用。
requestBody:
required: true
content:
@@ -201,7 +372,73 @@ paths:
schema:
$ref: '#/components/schemas/PocketBaseAuthResponse'
'400':
description: 参数错误
description: 参数错误或微信侧身份换取失败
'401':
description: PocketBase 原生认证失败
'415':
description: 请求体必须为 application/json
'429':
description: 重复请求过于频繁
'500':
description: 保存 auth 用户失败或服务端内部错误
/api/platform/register:
post:
tags: [平台认证]
summary: 平台用户注册
description: |
创建平台用户 auth record。
服务端会自动生成 GUID 并写入统一身份字段 `openid`,同时写入 `users_idtype = ManagePlatform`。
前端以 `users_phone + password/passwordConfirm` 注册,但服务端仍会创建 PocketBase 原生 auth 用户。
注册成功后直接返回 PocketBase 原生 auth token。
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformRegisterRequest'
responses:
'200':
description: 注册成功
content:
application/json:
schema:
$ref: '#/components/schemas/PocketBaseAuthResponse'
'400':
description: 参数错误或手机号已存在
'500':
description: GUID 生成失败、auth identity 缺失或保存用户失败
'415':
description: 请求体必须为 application/json
'429':
description: 重复请求过于频繁
/api/platform/login:
post:
tags: [平台认证]
summary: 平台用户登录
description: |
前端使用平台注册时保存的 `users_phone + password` 登录。
仅允许 `users_idtype = ManagePlatform` 的用户通过该接口登录。
服务端会先按手机号定位平台用户,再使用该用户的 PocketBase 原生 identity当前为 `email`)执行原生 password auth。
登录成功后直接返回 PocketBase 原生 auth token。
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformLoginRequest'
responses:
'200':
description: 登录成功
content:
application/json:
schema:
$ref: '#/components/schemas/PocketBaseAuthResponse'
'400':
description: 参数错误、密码错误或用户类型不匹配
'404':
description: 平台用户不存在
'500':
description: 平台用户缺少原生登录 identity 或服务端内部错误
'415':
description: 请求体必须为 application/json
'429':
@@ -210,6 +447,9 @@ paths:
post:
tags: [微信认证]
summary: 更新微信用户资料
description: |
基于当前 `Authorization` 对应 auth record 中的统一 `openid` 定位当前微信用户。
当前接口仍用于微信资料完善场景。
security:
- bearerAuth: []
requestBody:
@@ -231,23 +471,6 @@ paths:
data:
$ref: '#/components/schemas/WechatProfileResponseData'
'401':
description: token 无效或当前 auth record 缺少 openid
/api/wechat/refresh-token:
post:
tags: [微信认证]
summary: 刷新 PocketBase 原生 token
description: |
当前实现完全基于 PocketBase 原生鉴权,直接从当前 `Authorization` 对应的 auth record 读取 openid 并重新返回原生 auth token。
security:
- bearerAuth: []
responses:
'200':
description: 刷新成功
content:
application/json:
schema:
$ref: '#/components/schemas/PocketBaseAuthResponse'
'401':
description: token 无效或当前 auth record 缺少 openid
'404':
description: 用户不存在
description: token 无效或当前 auth record 缺少统一身份字段 openid
'400':
description: 参数错误、手机号已被注册或资料更新失败