Files
huang df76e33105 feat: 实现 C 端完整认证系统(client-auth-system)
实现面向个人客户的 7 个认证接口(A1-A7),覆盖资产验证、
微信公众号/小程序登录、手机号绑定/换绑、退出登录完整流程。

主要变更:
- 新增 PersonalCustomerOpenID 模型,支持多 AppID 多 OpenID 管理
- 实现有状态 JWT(JWT + Redis 双重校验),支持服务端主动失效
- 扩展微信 SDK:小程序 Code2Session + 3 个 DB 动态工厂函数
- 实现 A1 资产验证 IP 限流(30/min)和 A4 三层验证码限流
- 新增 7 个错误码(1180-1186)和 6 个 Redis Key 函数
- 注册 /api/c/v1/auth/* 下 7 个端点并更新 OpenAPI 文档
- 数据库迁移 000083:新建 tb_personal_customer_openid 表
2026-03-19 11:33:41 +08:00

5.5 KiB
Raw Permalink Blame History

C 端认证系统功能总结

概述

本次实现了面向个人客户C 端)的完整认证体系,替代旧 H5 登录接口。支持微信公众号和小程序两种登录方式,基于「资产标识符验证 → 微信授权 → 自动绑定资产 → 可选绑定手机号」的流程。

接口列表

接口 路径 认证 说明
A1 POST /api/c/v1/auth/verify-asset 资产标识符验证,返回 asset_token
A2 POST /api/c/v1/auth/wechat-login 微信公众号登录
A3 POST /api/c/v1/auth/miniapp-login 微信小程序登录
A4 POST /api/c/v1/auth/send-code 发送手机验证码
A5 POST /api/c/v1/auth/bind-phone 首次绑定手机号
A6 POST /api/c/v1/auth/change-phone 换绑手机号(双验证码)
A7 POST /api/c/v1/auth/logout 退出登录

登录流程

用户输入资产标识符SN/IMEI/ICCID
    │
    ▼
[A1] verify-asset → asset_token5分钟有效
    │
    ▼
微信授权(前端完成)
    │
    ├── 公众号 → [A2] wechat-login (code + asset_token)
    └── 小程序 → [A3] miniapp-login (code + asset_token)
                    │
                    ▼
             解析 asset_token → 获取微信 openid
             → 查找/创建客户 → 绑定资产
             → 签发 JWT + Redis 存储
                    │
                    ▼
             返回 { token, need_bind_phone, is_new_user }
                    │
                    ▼
             need_bind_phone == true?
                 YES → [A4] 发送验证码 → [A5] 绑定手机号
                 NO  → 进入主页面

核心设计

有状态 JWTJWT + Redis

  • JWT payload 仅含 customer_id + exp
  • 登录时将 token 写入 RedisTTL 与 JWT 一致
  • 每次请求在中间件同时校验 JWT 签名和 Redis 有效状态
  • 支持服务端主动失效(封禁、强制下线、退出登录)
  • 单点登录:新登录覆盖旧 token

OpenID 多记录管理

  • 新增 tb_personal_customer_openid
  • 同一客户可在多个 AppID公众号/小程序)下拥有不同 OpenID
  • 唯一约束:UNIQUE(app_id, open_id) WHERE deleted_at IS NULL
  • 客户查找逻辑openid 精确匹配 → unionid 回退合并 → 创建新客户

资产绑定

  • 每次登录创建 PersonalCustomerDevice 绑定记录
  • 同一资产允许被多个客户绑定(支持转手场景)
  • 首次绑定时自动将资产状态从「在库(1)」更新为「已销售(2)」

微信配置动态加载

  • 登录时从数据库 tb_wechat_config 动态读取激活配置
  • 优先走 WechatConfigService 的 Redis 缓存
  • 小程序登录直接 HTTP 调用微信 jscode2session(不依赖 PowerWeChat SDK

限流策略

接口 维度 限制
A1 IP 30 次/分钟
A4 手机号 60 秒冷却
A4 IP 20 次/小时
A4 手机号 10 次/天

新增/修改文件

新增文件

文件 说明
internal/model/personal_customer_openid.go OpenID 关联模型
internal/model/dto/client_auth_dto.go A1-A7 请求/响应 DTO
internal/store/postgres/personal_customer_openid_store.go OpenID Store
internal/service/client_auth/service.go 认证 Service核心业务逻辑
internal/handler/app/client_auth.go 认证 Handler7 个端点)
pkg/wechat/miniapp.go 小程序 SDK 封装
migrations/000083_add_personal_customer_openid.up.sql 迁移文件
migrations/000083_add_personal_customer_openid.down.sql 回滚文件

修改文件

文件 说明
internal/middleware/personal_auth.go 增加 Redis 双重校验
pkg/constants/redis.go 新增 token 和限流 Redis Key
pkg/errors/codes.go 新增错误码 1180-1186
pkg/config/defaults/config.yaml 新增 client.require_phone_binding
pkg/wechat/wechat.go 新增 MiniAppServiceInterface
pkg/wechat/config.go 新增 3 个 DB 动态工厂函数
internal/bootstrap/types.go 新增 ClientAuth Handler 字段
internal/bootstrap/handlers.go 实例化 ClientAuth Handler
internal/bootstrap/services.go 初始化 ClientAuth Service
internal/bootstrap/stores.go 初始化 OpenID Store
internal/routes/personal.go 注册 7 个认证端点
cmd/api/docs.go 注册文档生成器
cmd/gendocs/main.go 注册文档生成器

错误码

码值 常量名 说明
1180 CodeAssetNotFound 资产不存在
1181 CodeWechatConfigUnavailable 微信配置不可用
1182 CodeSmsSendFailed 短信发送失败
1183 CodeVerificationCodeInvalid 验证码错误或已过期
1184 CodePhoneAlreadyBound 手机号已被其他客户绑定
1185 CodeAlreadyBoundPhone 已绑定手机号不可重复绑定
1186 CodeOldPhoneMismatch 旧手机号与当前绑定不匹配

数据库变更

  • 新建表 tb_personal_customer_openid(迁移 000083
  • 唯一索引:idx_pco_app_id_open_id (app_id, open_id) 软删除条件
  • 普通索引:idx_pco_customer_id (customer_id)
  • 条件索引:idx_pco_union_id (union_id) WHERE union_id != ''

配置项

配置路径 环境变量 默认值 说明
client.require_phone_binding JUNHONG_CLIENT_REQUIRE_PHONE_BINDING true 是否要求绑定手机号