This commit is contained in:
jeremygan2021
2026-02-12 17:37:45 +08:00
parent abb1fe7c5e
commit 1e13882df3
3 changed files with 66 additions and 32 deletions

View File

@@ -1004,9 +1004,9 @@ def wechat_login(request):
phone_number = None
if phone_code:
access_token = get_access_token(config)
if access_token:
try:
try:
access_token = get_access_token(config)
if access_token:
phone_url = f"https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={access_token}"
phone_res = requests.post(phone_url, json={'code': phone_code}, timeout=5)
phone_data = phone_res.json()
@@ -1014,8 +1014,13 @@ def wechat_login(request):
if phone_data.get('errcode') == 0:
phone_info = phone_data.get('phone_info')
phone_number = phone_info.get('purePhoneNumber')
except Exception as e:
print(f"获取手机号失败: {e}")
else:
print(f"获取手机号API返回错误: {phone_data}")
else:
print("获取 AccessToken 失败,无法解密手机号")
except Exception as e:
print(f"获取手机号异常: {str(e)}")
try:
with transaction.atomic():
@@ -1029,29 +1034,41 @@ def wechat_login(request):
if mp_user and phone_user:
if mp_user != phone_user:
# 【合并场景】: 小程序用户 和 手机号用户 都存在且不同 -> 将手机号用户(Web)合并到小程序用户
# 注意: 如果 phone_user 也是真实的 MP 用户(有 openid 且不是 web_), 则可能冲突,这里默认保留当前登录的 mp_user
# 【合并场景】: 小程序用户 和 手机号用户 都存在且不同
# 1. 迁移订单
Order.objects.filter(wechat_user=phone_user).update(wechat_user=mp_user)
# 2. 迁移社区数据 (延迟导入避免循环引用)
from community.models import ActivitySignup, Topic, Reply
ActivitySignup.objects.filter(user=phone_user).update(user=mp_user)
Topic.objects.filter(author=phone_user).update(author=mp_user)
Reply.objects.filter(author=phone_user).update(author=mp_user)
# 3. 迁移分销员
if hasattr(phone_user, 'distributor') and not hasattr(mp_user, 'distributor'):
dist = phone_user.distributor
dist.user = mp_user
dist.save()
# 检查 phone_user 是否已经是真实的 MP 用户 (防止覆盖已绑定的其他微信账号)
# 规则: 如果 phone_user.openid 不是以 'web_' 开头,说明它已经是一个微信用户
# 此时我们不能简单的合并,因为这意味着两个不同的微信账号绑定了同一个手机号(可能是异常或用户更换了微信号)
# 策略: 优先保留当前的 mp_user提示用户手机号已被占用或者这里简单处理为不合并手机号只登录 mp_user
# 删除旧用户
phone_user.delete()
user = mp_user
# 更新手机号
if not user.phone_number:
user.phone_number = phone_number
if not phone_user.openid.startswith('web_'):
print(f"冲突: 手机号 {phone_number} 已被用户 {phone_user.id} (OpenID: {phone_user.openid}) 绑定,无法合并到当前用户 {mp_user.id}")
# 这种情况下,我们让当前用户登录,但不更新手机号 (或者可以返回错误提示需人工解绑)
user = mp_user
# 也可以选择强制更新手机号到当前用户,并解绑旧用户(取决于业务规则,这里选择保守策略:不合并,仅登录)
else:
# 是 Web 虚拟用户,可以安全合并
# 1. 迁移订单
Order.objects.filter(wechat_user=phone_user).update(wechat_user=mp_user)
# 2. 迁移社区数据 (延迟导入避免循环引用)
from community.models import ActivitySignup, Topic, Reply
ActivitySignup.objects.filter(user=phone_user).update(user=mp_user)
Topic.objects.filter(author=phone_user).update(author=mp_user)
Reply.objects.filter(author=phone_user).update(author=mp_user)
# 3. 迁移分销员
if hasattr(phone_user, 'distributor') and not hasattr(mp_user, 'distributor'):
dist = phone_user.distributor
dist.user = mp_user
dist.save()
# 删除旧用户
phone_user.delete()
user = mp_user
# 更新手机号
if not user.phone_number:
user.phone_number = phone_number
user.save()
else:
# 同一个用户
user = mp_user
@@ -1059,31 +1076,46 @@ def wechat_login(request):
elif phone_user:
# 【绑定场景】: 只有手机号用户存在 (通常是 Web 用户) -> 升级为小程序用户
user = phone_user
# 只有当它是 Web 虚拟用户时,才覆盖 OpenID
# 或者如果它就是目标用户,直接更新
if user.openid.startswith('web_') or not user.openid:
user.openid = openid
user.save()
elif user.openid != openid:
# 冲突: 手机号已被另一个真实 OpenID 绑定,但当前登录的是新的 OpenID
# 策略: 创建新用户,不合并 (避免安全风险)
user = WeChatUser.objects.create(openid=openid)
# 检查 openid 是否已被其他用户占用 (理论上 mp_user 为 None 说明没有,但双重检查)
existing_openid_user = WeChatUser.objects.filter(openid=openid).first()
if existing_openid_user:
user = existing_openid_user
else:
user = WeChatUser.objects.create(openid=openid)
# 此时不绑定手机号,因为手机号被 phone_user 占用了
elif mp_user:
# 【更新场景】: 只有小程序用户存在 -> 更新手机号
user = mp_user
if phone_number:
# 检查手机号是否冲突 (理论上 phone_user 为 None 说明没有冲突)
user.phone_number = phone_number
user.save()
else:
# 【新建场景】: 都不存在 -> 创建新用户
user = WeChatUser.objects.create(openid=openid)
if phone_number:
user.phone_number = phone_number
user.save()
# 统一更新会话信息
user.session_key = session_key
user.unionid = unionid
user.save()
# 统一更新会话信息 (确保 user 对象是最新的)
# 重新获取对象以防状态不一致 (可选,但推荐)
# user.refresh_from_db()
if user.openid == openid:
user.session_key = session_key
user.unionid = unionid
user.save()
created = False # 简化处理
except Exception as e: