Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 40s
feat(pay): 添加支付API基础结构 feat(miniapp): 创建支付测试小程序页面与配置 feat(wechatpay): 配置微信支付参数与证书 fix(guild): 修复成员列表查询条件 docs: 更新代码规范文档与需求文档 style: 统一前后端枚举显示与注释格式 refactor(admin): 重构用户奖励发放接口参数处理 test(title): 添加称号效果参数验证测试
38 lines
3.4 KiB
Markdown
38 lines
3.4 KiB
Markdown
## 问题定位
|
||
- 现象:POST `/api/pay/wechat/notify` 返回 400,日志提示“certificate [PUB_KEY_ID_0116104396352025041000211519001600] not found in verifier”。
|
||
- 原因:微信侧请求头 `Wechatpay-Serial` 为 `PUB_KEY_ID_*` 格式,说明该商户已启用“微信支付平台公钥”模式;当前代码仅使用“平台证书”验签(`verifiers.NewSHA256WithRSAVerifier` + `downloader`),导致找不到匹配的证书序列号而验签失败。
|
||
- 代码位置:
|
||
- 路由注册:`internal/router/router.go:252`
|
||
- 回调处理:`internal/api/pay/wechat_notify.go:40-46`(注册证书下载器+证书验签器)
|
||
- 客户端初始化:`internal/pkg/pay/client.go:32-39`(`WithWechatPayAutoAuthCipher` 使用平台证书模式)
|
||
|
||
## 修复方案
|
||
- 增加“平台公钥”模式配置并切换验签/签名实现:
|
||
- 在配置新增 `wechatpay.public_key_id` 与 `wechatpay.public_key_path`(商户后台下载的 `pub_key.pem` 与对应 `PUB_KEY_ID_*`)。
|
||
- 回调验签:当检测到已配置公钥,改用 `verifiers.NewSHA256WithRSAPubkeyVerifier(publicKeyID, publicKey)` 构造 `notify.Handler`;否则保持现有证书模式。
|
||
- 请求侧签名与自动加密:当检测到已配置公钥,改用 `option.WithWechatPayPublicKeyAuthCipher(mchid, serialNo, privateKey, publicKeyID, publicKey)` 初始化 `core.Client`;否则保持 `WithWechatPayAutoAuthCipher`。
|
||
- 初始化时机优化:
|
||
- 将证书下载器注册/公钥加载前置至应用启动阶段,避免首次回调时的“尚未拉取证书”竞态问题。
|
||
- 兼容策略:
|
||
- 双模式自动选择:优先检测公钥配置;缺省走证书模式,确保对旧商户不破坏。
|
||
|
||
## 实施步骤
|
||
- 配置:
|
||
- 在 `configs/*.toml` 的 `[wechatpay]` 增加 `public_key_id` 与 `public_key_path` 键;同时支持环境变量覆盖(如 `WECHAT_PUBLIC_KEY_ID`、`WECHAT_PUBLIC_KEY_PATH`)。
|
||
- 代码改动:
|
||
- `internal/api/pay/wechat_notify.go`:根据配置分支选择 `verifiers.NewSHA256WithRSAPubkeyVerifier` 或现有证书验签器;加载公钥使用 `utils.LoadPublicKeyWithPath`。
|
||
- `internal/pkg/pay/client.go`:根据配置分支选择 `option.WithWechatPayPublicKeyAuthCipher` 或现有证书选项。
|
||
- 启动流程:在应用初始化位置集中完成下载器注册/公钥加载与复用,不在每次回调时重复注册。
|
||
|
||
## 验证步骤
|
||
- 本地联调:
|
||
- 使用真实微信回调数据(包含 `Wechatpay-Serial: PUB_KEY_ID_*`)验证回调成功返回 `{"code":"SUCCESS","message":"OK"}`。
|
||
- 下单→支付→回调链路验证:检查订单状态从 1→2,`paidAt` 按回调 `success_time` 生效(`internal/api/pay/wechat_notify.go:67-71`)。
|
||
- 日志与安全:
|
||
- 打印初始化模式(证书/公钥)与关键配置是否完整,避免静默失败。
|
||
- 不输出密钥/私钥内容,符合安全规范。
|
||
|
||
## 额外检查(关于“req 没有写”)
|
||
- 当前回调处理直接使用 `ctx.Request()` 原始请求体(`internal/api/pay/wechat_notify.go:48`),未提前读取/篡改;若上游中间件读取了 `Body`,需保证使用 `io.NopCloser` 复位请求体后再交给 `notify.Handler`。本次改造同时确认路由链路未破坏请求体传递。
|
||
|
||
请确认是否按照“平台公钥”接入(已具备 `pub_key.pem` 与 `PUB_KEY_ID_*`)。确认后我将按上述方案实现代码与配置改动,并完成联调与验证。 |