fix: 手机号认证按俱乐部 wx_appid 换 token,修复星之界 40013

This commit is contained in:
XingQue
2026-06-25 01:11:32 +08:00
parent 4714e2259b
commit cca53bbc96
2 changed files with 71 additions and 31 deletions

View File

@@ -610,7 +610,7 @@ class UserInfoUpdateView(APIView):
# 手机号 —— 极简可靠版
code = request.data.get('shoujihao_code')
if code:
phone = self._get_phone_safe(code)
phone = self._get_phone_safe(code, request)
if phone is None:
return Response({'code': 6, 'msg': '手机号获取失败,请重新授权', 'data': None}, status=400)
user.Phone = phone
@@ -630,35 +630,47 @@ class UserInfoUpdateView(APIView):
return Response({'code': 99, 'msg': str(e), 'data': None}, status=500)
# ---------- 安全手机号(内存去重) ----------
def _get_phone_safe(self, code):
# 如果已经处理过这个code直接返回结果
if code in self._phone_cache:
cached = self._phone_cache[code]
def _get_phone_safe(self, code, request):
cache_key = f'{code}:{self._resolve_wx_club_id(request, request.user)}'
if cache_key in self._phone_cache:
cached = self._phone_cache[cache_key]
return cached if cached != '__FAIL__' else None
# 标记处理中(简单防重入)
self._phone_cache[code] = '__PROCESSING__'
self._phone_cache[cache_key] = '__PROCESSING__'
try:
phone = self._call_wechat(code)
self._phone_cache[code] = phone
phone = self._call_wechat(code, request)
self._phone_cache[cache_key] = phone
return phone
except Exception as e:
logger.error(f"微信调用失败: {str(e)}")
self._phone_cache[code] = '__FAIL__'
self._phone_cache[cache_key] = '__FAIL__'
return None
# ---------- 微信接口调用每次全新token ----------
def _call_wechat(self, code):
token = self._get_new_token()
def _resolve_wx_club_id(self, request, user):
"""手机号 code 与小程序 appid 绑定,须用对应俱乐部的 wx 配置换 token。"""
from jituan.constants import CLUB_ID_DEFAULT
from jituan.services.club_context import resolve_club_id_from_request
from jituan.services.club_user import get_user_club_id
club_id = resolve_club_id_from_request(request)
if club_id == CLUB_ID_DEFAULT:
user_club = get_user_club_id(user)
if user_club:
return user_club
return club_id
# ---------- 微信接口调用(按俱乐部 appid 换 token ----------
def _call_wechat(self, code, request):
club_id = self._resolve_wx_club_id(request, request.user)
token = self._get_new_token(club_id, force_refresh=True)
url = f'https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={token}'
resp = requests.post(url, json={'code': code}, timeout=10)
data = resp.json()
errcode = data.get('errcode')
if errcode == 0:
return data['phone_info']['purePhoneNumber']
# 即使刚拿的token也可能意外失效重试一次
if errcode == 40001:
token = self._get_new_token()
token = self._get_new_token(club_id, force_refresh=True)
url = f'https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={token}'
resp = requests.post(url, json={'code': code}, timeout=10)
data = resp.json()
@@ -666,22 +678,13 @@ class UserInfoUpdateView(APIView):
return data['phone_info']['purePhoneNumber']
raise Exception(f"微信错误(errcode={errcode}): {data.get('errmsg')}")
# ---------- 获取全新 access_token不缓存每次调微信 ----------
def _get_new_token(self):
appid = getattr(settings, 'WEIXIN_APPID', '')
secret = getattr(settings, 'WEIXIN_SECRET', '')
if not appid or not secret:
raise Exception('缺少微信配置')
resp = requests.get('https://api.weixin.qq.com/cgi-bin/token', params={
'grant_type': 'client_credential',
'appid': appid,
'secret': secret
})
data = resp.json()
token = data.get('access_token')
def _get_new_token(self, club_id, force_refresh=False):
from utils.weixin_token import get_club_mini_access_token
token = get_club_mini_access_token(club_id, force_refresh=force_refresh)
if token:
return token
raise Exception(f"获取access_token失败: {data}")
raise Exception(f'俱乐部 {club_id} 缺少微信配置或获取 access_token 失败')
# ---------- 工具 ----------
def _get_or_create_boss(self, user):