feat(auth): 微信登录与手机号绑定 / 占用冲突处理(M2 + M3 §10) #139
Reference in New Issue
Block a user
Delete Branch "feat/wechat-login"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
背景 / 需求
新增「微信登录」链路:用户用微信授权登录 App。openid 已绑账号即直接登入;
未绑则走「绑手机号」建号,并处理「手机号已被别的账号占用」的冲突(M2),
以及绑微信后展示昵称/头像的替换策略(M3 §10)。
关键取舍:微信登录不套用钱包提现里 bind-wechat 的「撞号即 409」逻辑
——登录场景 openid 命中就应登入,不能因撞号把用户挡在门外。
改动概览:新增 5 个端点(前缀
/api/v1/auth)/wechat-loginbind_ticket,返回need_bind_phone(此刻不建号);未配 APP_ID/SECRET→503/wechat/bind-phone/smsbind_ticket+ 手机号 + 短信码绑号/wechat/bind-phone/jverifybind_ticket+ 极光本机号一键取号绑号/wechat/conflict/continue/wechat/conflict/rebind绑号两条取号路径(sms / jverify)尾段共用
_finish_wechat_bind:手机号未注册→建微信账号(channel=wechat,昵称头像取微信)登入;
已被占用→返回
phone_occupied(带占用账号昵称/头像/注册时间/has_wechat、conflict_ticket、rebind_available、rebind_blocked_days),交前端冲突页。冲突页三选一,后端提供 continue / rebind 两个动作(「取消」为前端本地行为)。
关键设计
两种短时令牌(
core/security.py,复用JWT_SECRET_KEY,靠typ区分):bind_ticket(typ=wechat_bind,sub=openid,附微信昵称/头像,TTL 10min):openid 未命中时下发,覆盖「授权→输手机号→收码→验码」整个绑定流程。
conflict_ticket(typ=wechat_conflict):比 bind_ticket 多编码已验证的手机号;换绑 / 继续绑定只认票里的 phone,堵住「拿别人手机号去夺号」的接管漏洞。
30 天换绑限制: 新增台账表
phone_rebind_log(手机号级、渠道无关),记录「腾号重建」这一破坏性事件,靠
rebound_at算窗口;阈值走配置
PHONE_REBIND_LIMIT_DAYS。命中限制的换绑请求返回 409。M3 §10 昵称/头像替换: 绑微信默认用微信昵称/头像替换展示,
抽成共享 helper,登录绑号路径与钱包绑微信路径两处共用
(故
wallet.py、tests/test_withdraw.py一并有改动)。