diff --git a/jituan/services/club_resolver.py b/jituan/services/club_resolver.py index ef11605..0d9a796 100644 --- a/jituan/services/club_resolver.py +++ b/jituan/services/club_resolver.py @@ -1,5 +1,7 @@ """俱乐部微信配置与 openid 解析。""" import logging +import re + import requests from django.conf import settings @@ -8,6 +10,8 @@ from jituan.models import Club logger = logging.getLogger(__name__) +_REFERER_APPID_RE = re.compile(r'servicewechat\.com/(wx[0-9a-fA-F]+)/', re.I) + def resolve_club_by_appid(app_id): if not app_id: @@ -38,6 +42,45 @@ def get_club_wx_credentials(club_id): return '', '', club +def resolve_club_id_for_wechat_request(request): + """ + 小程序请求解析 club_id(登录/扫码注册)。 + 优先级:X-Club-Id > body.appId > Referer 内 wx appid > 默认 xq。 + 老端 fighter.js 的 wdlyhdl 未带头时,靠 Referer 识别星之界等俱乐部。 + """ + from jituan.services.club_context import resolve_club_id_from_request + + header = (request.META.get('HTTP_X_CLUB_ID') or '').strip() + if not header and hasattr(request, 'headers'): + header = (request.headers.get('X-Club-Id') or '').strip() + if header: + return header + + app_id = '' + data = getattr(request, 'data', None) or {} + if isinstance(data, dict): + app_id = (data.get('appId') or data.get('app_id') or '').strip() + + if not app_id: + referer = request.META.get('HTTP_REFERER', '') or '' + matched = _REFERER_APPID_RE.search(referer) + if matched: + app_id = matched.group(1) + + if app_id: + club = resolve_club_by_appid(app_id) + if club: + return club.club_id + + return resolve_club_id_from_request(request) + + +def wechat_jscode2session_for_request(request, code): + """按请求上下文换取 openid(多俱乐部小程序)。""" + club_id = resolve_club_id_for_wechat_request(request) + return jscode2session(code, club_id=club_id) + + def jscode2session(code, club_id=None, app_id=None): """ 按俱乐部微信配置换取 openid。 diff --git a/jituan/services/invite_guard.py b/jituan/services/invite_guard.py index 468478c..ec43e9a 100644 --- a/jituan/services/invite_guard.py +++ b/jituan/services/invite_guard.py @@ -1,5 +1,5 @@ """邀请码 / 邀请链俱乐部隔离。""" -from jituan.services.club_context import resolve_club_id_from_request +from jituan.services.club_resolver import resolve_club_id_for_wechat_request from jituan.services.club_user import get_user_club_id @@ -9,7 +9,7 @@ def assert_invite_same_club(request, inviter_user, invitee_user=None): 现网全部 xq 时行为与改造前一致。 返回 (ok, message) """ - club_id = resolve_club_id_from_request(request) + club_id = resolve_club_id_for_wechat_request(request) inviter_club = get_user_club_id(inviter_user) if inviter_club != club_id: return False, '邀请码不属于当前小程序俱乐部' diff --git a/users/views/auth.py b/users/views/auth.py index 951c51e..6bffdd6 100644 --- a/users/views/auth.py +++ b/users/views/auth.py @@ -113,8 +113,9 @@ class WechatMiniProgramLoginView(APIView): return Response({'code': 1, 'msg': '微信授权码不能为空', 'data': None}, status=status.HTTP_400_BAD_REQUEST) - # 获取微信openid和unionid - wechat_data = self.get_wechat_openid(code) + # 获取微信openid和unionid(按俱乐部小程序配置) + from jituan.services.club_resolver import wechat_jscode2session_for_request + wechat_data = wechat_jscode2session_for_request(request, code) if not wechat_data or 'openid' not in wechat_data: error_msg = wechat_data.get('errmsg', '微信授权失败') return Response({'code': 2, 'msg': f'微信登录失败: {error_msg}', 'data': None}, @@ -833,10 +834,16 @@ class WechatLoginAndDashouRegisterView(APIView): 'data': None }, status=status.HTTP_400_BAD_REQUEST) - # 2. 获取微信openid - wechat_data = self.get_wechat_openid(code) + # 2. 获取微信openid(按俱乐部小程序 appid,勿用全局星阙配置) + from jituan.services.club_resolver import ( + resolve_club_id_for_wechat_request, + wechat_jscode2session_for_request, + ) + club_id = resolve_club_id_for_wechat_request(request) + wechat_data = wechat_jscode2session_for_request(request, code) if not wechat_data or 'openid' not in wechat_data: error_msg = wechat_data.get('errmsg', '微信授权失败') + logger.warning('wdlyhdl 微信登录失败 club=%s err=%s', club_id, error_msg) return Response({ 'code': 4, 'msg': f'微信登录失败: {error_msg}', @@ -880,7 +887,7 @@ class WechatLoginAndDashouRegisterView(APIView): from jituan.services.invite_guard import assert_invite_same_club from jituan.services.club_user import ensure_user_club_id - from jituan.services.club_context import resolve_club_id_from_request + from jituan.services.club_resolver import resolve_club_id_for_wechat_request ok, invite_msg = assert_invite_same_club( request, guanshi_profile.user, user_main, @@ -892,7 +899,7 @@ class WechatLoginAndDashouRegisterView(APIView): 'data': None }, status=status.HTTP_403_FORBIDDEN) - ensure_user_club_id(user_main, resolve_club_id_from_request(request)) + ensure_user_club_id(user_main, resolve_club_id_for_wechat_request(request)) # 验证管事状态 @@ -1261,7 +1268,8 @@ class WechatLoginAndGuanshiRegisterView(APIView): return Response({'code': 400, 'msg': '邀请码长度超过限制', 'data': None}, status=status.HTTP_400_BAD_REQUEST) - wechat_data = self._get_wechat_openid(code) + from jituan.services.club_resolver import wechat_jscode2session_for_request + wechat_data = wechat_jscode2session_for_request(request, code) if not wechat_data or 'openid' not in wechat_data: error_msg = wechat_data.get('errmsg', '微信授权失败') return Response({'code': 400, 'msg': f'微信登录失败: {error_msg}', 'data': None},