123 lines
3.9 KiB
Python
123 lines
3.9 KiB
Python
"""俱乐部微信配置与 openid 解析。"""
|
||
import logging
|
||
import re
|
||
|
||
import requests
|
||
from django.conf import settings
|
||
|
||
from jituan.constants import CLUB_ID_DEFAULT
|
||
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:
|
||
return None
|
||
try:
|
||
return Club.query.filter(wx_appid=app_id, status=1).first()
|
||
except Exception:
|
||
return Club.objects.filter(wx_appid=app_id, status=1).first()
|
||
|
||
|
||
def get_club_wx_credentials(club_id):
|
||
"""优先读 club 表;xq 缺省时回退 settings 全局配置(兼容现网)。"""
|
||
club_id = club_id or CLUB_ID_DEFAULT
|
||
try:
|
||
club = Club.query.get(club_id=club_id)
|
||
except Club.DoesNotExist:
|
||
club = None
|
||
|
||
if club and club.wx_appid and club.wx_secret:
|
||
return club.wx_appid, club.wx_secret, club
|
||
|
||
if club_id == CLUB_ID_DEFAULT:
|
||
return (
|
||
getattr(settings, 'WEIXIN_APPID', ''),
|
||
getattr(settings, 'WEIXIN_SECRET', ''),
|
||
club,
|
||
)
|
||
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。
|
||
club_id 与 app_id 二选一;app_id 用于从小程序 appId 反查 club。
|
||
"""
|
||
club = None
|
||
if app_id:
|
||
club = resolve_club_by_appid(app_id)
|
||
club_id = club.club_id if club else club_id
|
||
appid, secret, club = get_club_wx_credentials(club_id)
|
||
if not appid or not secret:
|
||
return {'errmsg': '俱乐部微信配置未设置'}
|
||
|
||
url = 'https://api.weixin.qq.com/sns/jscode2session'
|
||
params = {
|
||
'appid': appid,
|
||
'secret': secret,
|
||
'js_code': code,
|
||
'grant_type': 'authorization_code',
|
||
}
|
||
try:
|
||
response = requests.get(url, params=params, timeout=10)
|
||
result = response.json()
|
||
if 'openid' in result:
|
||
return {
|
||
'openid': result['openid'],
|
||
'session_key': result.get('session_key', ''),
|
||
'unionid': result.get('unionid', ''),
|
||
'club_id': club_id or CLUB_ID_DEFAULT,
|
||
'wx_appid': appid,
|
||
}
|
||
errcode = result.get('errcode', 'unknown')
|
||
errmsg = result.get('errmsg', '未知错误')
|
||
return {'errmsg': f'[{errcode}]{errmsg}'}
|
||
except requests.exceptions.Timeout:
|
||
return {'errmsg': '请求微信接口超时'}
|
||
except Exception as e:
|
||
logger.exception('jscode2session 异常 club_id=%s', club_id)
|
||
return {'errmsg': f'请求微信接口异常: {str(e)}'}
|