# -*- coding: utf-8 -*- """微信小程序登录服务。 ``code2session`` 用小程序 ``wx.login`` 的 code 换取 openid。 未配置 ``WECHAT_APPID`` / ``WECHAT_SECRET`` 时走「测试直通」:直接把 code 当 openid 返回,便于无真实微信 appid 的环境联调(生产必须配置真实凭据)。 """ from __future__ import annotations import httpx from .. import config _WX_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session" class WechatError(Exception): """微信登录异常(code 无效 / 网络错误等)。""" async def code2session(code: str) -> str: """用登录 code 换取 openid。未配置 appid 时直通:``openid = code``。""" code = code.strip() if not config.WECHAT_APPID or not config.WECHAT_SECRET: return code try: async with httpx.AsyncClient(timeout=10) as client: resp = await client.get( _WX_SESSION_URL, params={ "appid": config.WECHAT_APPID, "secret": config.WECHAT_SECRET, "js_code": code, "grant_type": "authorization_code", }, ) data = resp.json() except Exception as exc: # noqa: BLE001 raise WechatError(f"wechat code2session request failed: {exc}") from exc errcode = data.get("errcode", 0) if errcode: raise WechatError( f"wechat code2session error {errcode}: {data.get('errmsg', '')}" ) openid = data.get("openid") if not openid: raise WechatError("wechat code2session returned no openid") return openid