07955ddf07
服务号「植趣 ZeeQ」已认证,走网页授权(snsapi_base,只拿 openid、用户无感), 不接管消息推送,副作用最小。 流程:PC 建 ticket → 二维码指向 /wx/mp?t= → 用户微信扫码 → 302 到微信授权页 → 回调 /api/v1/wx/mp/callback 用 code 换 openid → 找/建用户 → ticket 置 authorized → PC 轮询 /wx/mp/poll 拿到 authorized → 签发 JWT。ticket 一次性消费防重放。 - 配置(appid/secret/base_url)后台可改,secret AES 加密入库,与微信支付同一套 secrets; - ticket 存 Redis(短 TTL),无 Redis 时回退进程内内存(本地单实例可用,生产必须有 Redis); - User 加 wechat_openid。**部分唯一索引**(WHERE openid <> '')而非普通唯一: 存量邮箱用户该列是空串,普通唯一索引会让多个空串互撞、AutoMigrate 直接失败 —— 与之前 NULL 余额同类的坑,这次提前避开。 单测覆盖:授权 URL 拼接(含 #wechat_redirect 锚点必须在末尾)、secret 加密往返、 建号/查号、空 openid 不误命中存量用户。微信 API 调用依赖公网回调,本地测不了, 留待部署后真机扫码。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
36 lines
1002 B
Go
36 lines
1002 B
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
)
|
|
|
|
// 微信首次登录建号:无邮箱、按 openid 可查回。
|
|
func TestCreateAndGetWechatUser(t *testing.T) {
|
|
p := newTestStore(t)
|
|
ctx := context.Background()
|
|
|
|
// 不存在时返回 (nil, nil),不报错
|
|
if u, err := p.GetUserByWechatOpenID(ctx, "openid-x"); err != nil || u != nil {
|
|
t.Fatalf("未建号应返回 nil,nil,得 %v,%v", u, err)
|
|
}
|
|
|
|
u, err := p.CreateWechatUser(ctx, "openid-x", "微信用户")
|
|
if err != nil {
|
|
t.Fatalf("建号失败: %v", err)
|
|
}
|
|
if u.Email != "" {
|
|
t.Fatalf("微信用户不该有邮箱,得 %q", u.Email)
|
|
}
|
|
|
|
got, err := p.GetUserByWechatOpenID(ctx, "openid-x")
|
|
if err != nil || got == nil || got.ID != u.ID {
|
|
t.Fatalf("按 openid 查不回: %v,%v", got, err)
|
|
}
|
|
|
|
// 空 openid 查询不匹配任何人(避免存量邮箱用户的空串被 openid 查询命中)
|
|
if got, _ := p.GetUserByWechatOpenID(ctx, ""); got != nil {
|
|
t.Fatalf("空 openid 不该命中任何用户,得 %+v", got)
|
|
}
|
|
}
|