- 添加个人客户微信登录和手机验证码登录接口 - 实现个人客户设备、ICCID、手机号关联管理 - 添加短信发送服务(HTTP 客户端) - 添加微信认证服务(含 mock 实现) - 添加 JWT Token 生成和验证工具 - 创建数据库迁移脚本(personal_customer 关联表) - 修复测试文件中的路由注册参数错误 - 重构 scripts 目录结构(分离独立脚本到子目录) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
8.4 KiB
8.4 KiB
Change: 添加个人客户和微信登录
Why
个人客户是系统的重要用户群体,他们通过 H5/小程序访问系统,使用 ICCID/设备号登录并绑定微信。个人客户不参与 RBAC 权限体系,但需要独立的认证流程和数据存储。
What Changes
新增功能
- 个人客户登录流程: 通过 ICCID/设备号 + 微信授权登录,首次需绑定手机号
- 微信绑定: 存储 OpenID/UnionID 用于微信支付和通知(用户唯一标识)
- 个人客户认证中间件: 独立于 B 端账号的认证体系
- 短信验证码: 对接武汉聚惠富通行业短信平台发送验证码
- ICCID/设备号绑定记录: 记录微信用户使用过哪些 ICCID/设备号
核心业务模型
用户身份识别
- 个人客户 (PersonalCustomer) = 微信用户(通过
wx_open_id唯一标识) - ICCID/设备号 是独立的资源(可以被充值、使用),不是用户身份
- 任何人拿到 ICCID/设备号 都可以使用,没有所有权概念
数据模型关系
- PersonalCustomer: 微信用户主表(不存储手机号、ICCID)
- PersonalCustomerPhone: 微信用户绑定的手机号(一对多)
- PersonalCustomerICCID: 微信用户使用过的 ICCID 记录(多对多)
- PersonalCustomerDevice: 微信用户使用过的设备号记录(多对多,可选)
业务规则
- 用户身份:个人客户由微信 OpenID/UnionID 唯一标识
- 手机号绑定:一个微信用户可以绑定多个手机号(用于接收验证码)
- ICCID/设备号绑定:记录微信用户使用过哪些 ICCID/设备号(用于业务追踪)
- 充值业务:充值是充到 ICCID/设备号上,不是充到用户账户
登录流程
用户扫码/进入H5
↓
输入 ICCID/设备号(业务标识,不存储到用户表)
↓
微信授权登录
↓
获取 wx_open_id, wx_union_id
↓
检查微信用户是否存在
├─ 是 → 记录 ICCID 绑定关系 → 登录成功
└─ 否 → 创建新用户 → 提示绑定手机号
↓
输入手机号 → 发送验证码 → 验证
↓
创建手机号绑定记录 → 创建 ICCID 绑定记录 → 登录成功
数据模型设计
1. PersonalCustomer(个人客户 = 微信用户)
type PersonalCustomer struct {
ID uint // 主键
WxOpenID string // 微信OpenID(唯一标识,必填)
WxUnionID string // 微信UnionID(必填)
Nickname string // 微信昵称
AvatarURL string // 微信头像URL
Status int // 状态 0=禁用 1=启用
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
}
索引:
- 唯一索引:
wx_open_id(where deleted_at IS NULL) - 普通索引:
wx_union_id
说明:
- 移除
phone、iccid、imei字段 - 微信信息是唯一标识用户的字段
2. PersonalCustomerPhone(微信用户的手机号)
type PersonalCustomerPhone struct {
ID uint // 主键
CustomerID uint // 关联个人客户 ID(微信用户)
Phone string // 手机号
IsPrimary bool // 是否主手机号(用于通知等)
VerifiedAt time.Time // 验证通过时间
Status int // 状态 0=禁用 1=启用
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
}
索引:
- 唯一索引:
(customer_id, phone)(where deleted_at IS NULL) - 普通索引:
phone
说明:
- 一个微信用户可以绑定多个手机号
- 手机号用于接收验证码、通知等
3. PersonalCustomerICCID(ICCID 与微信用户的绑定关系)
type PersonalCustomerICCID struct {
ID uint // 主键
CustomerID uint // 关联个人客户 ID(微信用户)
ICCID string // ICCID(20位数字)
BindAt time.Time // 绑定时间
LastUsedAt time.Time // 最后使用时间
Status int // 状态 0=禁用 1=启用
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
}
索引:
- 唯一索引:
(customer_id, iccid)(where deleted_at IS NULL) - 普通索引:
iccid- 查询某个 ICCID 被哪些用户使用过
说明:
- 记录微信用户使用过哪些 ICCID
- 一个 ICCID 可以被多个微信用户使用过
- 一个微信用户可以使用多个 ICCID
4. PersonalCustomerDevice(设备号与微信用户的绑定关系,可选)
type PersonalCustomerDevice struct {
ID uint // 主键
CustomerID uint // 关联个人客户 ID(微信用户)
DeviceNo string // 设备号/IMEI
BindAt time.Time // 绑定时间
LastUsedAt time.Time // 最后使用时间
Status int // 状态 0=禁用 1=启用
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
}
索引:
- 唯一索引:
(customer_id, device_no)(where deleted_at IS NULL) - 普通索引:
device_no
说明:
- 记录微信用户使用过哪些设备号
- 与 ICCID 类似的多对多关系
Impact
- Affected specs: personal-customer (新建)
- Affected code:
internal/model/personal_customer.go- 需要修改(移除 phone 字段)internal/model/personal_customer_phone.go- 新增internal/model/personal_customer_iccid.go- 新增internal/model/personal_customer_device.go- 新增(可选)internal/store/postgres/personal_customer_store.go- 需要扩展internal/store/postgres/personal_customer_phone_store.go- 新增internal/store/postgres/personal_customer_iccid_store.go- 新增internal/service/personal_customer_service.go- 扩展登录逻辑internal/handler/personal_customer_handler.go- 新增internal/middleware/personal_auth.go- 个人客户认证中间件pkg/sms/- 短信验证码服务(对接武汉聚惠富通行业短信)config/config.yaml- 新增短信服务配置项migrations/- 新增数据库迁移脚本
依赖关系
本提案依赖 add-user-organization-model 提案中的 PersonalCustomer 模型定义。
短信服务对接方案
第三方服务信息
- 服务商: 武汉聚惠富通(行业短信)
- 接口网关:
https://gateway.sms.whjhft.com:8443/sms - 协议: HTTP JSON API v1.6
- 接口文档:
docs/第三方文档/SMS_HTTP_1.6.md
使用接口
短信批量发送接口: POST /api/sendMessageMass
发送方式: 直接发送内容(不使用短信模板)
短信内容格式: 【签名】自定义内容
- 签名部分需提前向服务商报备并审核通过
- 示例:
【签名】您的验证码是123456,5分钟内有效 - 不使用
templateId和params参数,只使用content字段
实现方案
-
包结构:
pkg/sms/client.go- 短信客户端封装types.go- 请求/响应类型定义error.go- 错误码映射
-
配置管理:
sms: gateway_url: "https://gateway.sms.whjhft.com:8443/sms" username: "账号用户名" password: "账号密码" signature: "【签名】" timeout: 10s -
核心功能:
- 生成 Sign 签名(MD5 计算)
- 发送验证码短信
- 错误处理和日志记录
- 超时和重试机制
-
安全要求:
- 短信密码不得硬编码,必须从配置文件读取
- Sign 计算遵循官方规范:
MD5(userName + timestamp + MD5(password)) - 时间戳与服务器时间误差不得超过5分钟
-
错误处理:
- 余额不足(code=5):记录错误日志,返回用户友好提示
- 时间戳错误(code=16):检查服务器时间同步
- 账号异常(code=3, 4):记录错误日志,通知管理员
- 其他错误:参考文档响应状态码列表
注意事项
- 数据模型变更:PersonalCustomer 模型需要移除
phone字段,新增 PersonalCustomerPhone、PersonalCustomerICCID 关联表 - 微信 SDK 集成:可以先预留接口或使用 Mock 实现,后续对接具体的微信 OAuth API
- 短信签名:需要提前向服务商报备,使用报备通过的签名
- 业务逻辑实现:本提案重点在数据模型建立,具体业务逻辑(登录流程、绑定流程)后续实现
- ICCID/设备号充值:充值是充到 ICCID/设备号资源上,不是充到用户账户,需与后续的资产模块协同设计