创赢未来评分系统 - 初始化提交(移除大文件)
All checks were successful
Deploy to Server / deploy (push) Successful in 18s

This commit is contained in:
爽哒哒
2026-03-18 22:28:45 +08:00
commit f26d35da66
315 changed files with 36043 additions and 0 deletions

88
backend/shop/utils.py Normal file
View File

@@ -0,0 +1,88 @@
import requests
from django.core.cache import cache
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from .models import WeChatPayConfig, WeChatUser
import logging
logger = logging.getLogger(__name__)
def get_current_wechat_user(request):
"""
根据 Authorization 头获取当前微信用户
增强逻辑:如果 Token 解析出的 OpenID 对应的用户不存在(可能已被合并删除),
但该 OpenID 是 Web 虚拟 ID (web_phone),尝试通过手机号查找现有的主账号。
"""
auth_header = request.headers.get('Authorization')
if not auth_header or not auth_header.startswith('Bearer '):
return None
token = auth_header.split(' ')[1]
signer = TimestampSigner()
try:
# 签名包含 openid
openid = signer.unsign(token, max_age=86400 * 30) # 30天有效
user = WeChatUser.objects.filter(openid=openid).first()
if user:
return user
# 如果没找到用户,检查是否是 Web 虚拟 OpenID
# 场景Web 用户已被合并到小程序账号,旧 Web Token 依然有效,指向合并后的账号
if openid.startswith('web_'):
try:
# 格式: web_13800138000
parts = openid.split('_', 1)
if len(parts) == 2:
phone = parts[1]
# 尝试通过手机号查找(查找合并后的主账号)
user = WeChatUser.objects.filter(phone_number=phone).first()
if user:
return user
except Exception:
pass
return None
except (BadSignature, SignatureExpired):
return None
def get_access_token(config=None, force_refresh=False):
"""
获取微信接口调用凭证 (client_credential)
"""
# 尝试从缓存获取
cache_key = 'wechat_access_token'
if config:
cache_key = f'wechat_access_token_{config.app_id}'
if not force_refresh:
token = cache.get(cache_key)
if token:
return token
if not config:
# 优先查找指定 AppID
config = WeChatPayConfig.objects.filter(app_id='wxdf2ca73e6c0929f0').first()
if not config:
config = WeChatPayConfig.objects.filter(is_active=True).first()
if not config or not config.app_id or not config.app_secret:
logger.error("No active WeChatPayConfig found or missing app_id/app_secret")
return None
url = f"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={config.app_id}&secret={config.app_secret}"
try:
response = requests.get(url, timeout=10)
data = response.json()
if 'access_token' in data:
token = data['access_token']
expires_in = data.get('expires_in', 7200)
# 缓存 Token留出 200 秒缓冲时间
cache.set(cache_key, token, expires_in - 200)
return token
else:
logger.error(f"获取 AccessToken 失败: {data}")
except Exception as e:
logger.error(f"获取 AccessToken 异常: {str(e)}", exc_info=True)
return None