Files
Scoring-System/backend/shop/utils.py
爽哒哒 f26d35da66
All checks were successful
Deploy to Server / deploy (push) Successful in 18s
创赢未来评分系统 - 初始化提交(移除大文件)
2026-03-18 22:41:23 +08:00

89 lines
3.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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