文件
yjyf/utils/wxlogin.js
linda ca998d0ef1 chore(config): 微信登录配置加固 + 配置自检脚本
配置:
- manifest.json mp-weixin.appid = wx40ca4b02d4d1cb58(构建产物已自动同步)
- .env 新增 [sms] 段:mock / mock_code,手机号登录验证码改为配置驱动
  (Auth::login 不再硬编码 123456;mock=0 时返回 2010 提示接入短信)
- 服务端 .env [wechat] appid/secret 已就位并与小程序一致

加固:
- 新增 utils/wxlogin.js:微信登录单飞(防静默登录与手动登录抢同一个一次性 code)
  + 40029/40163 自动换新 code 重试一次
- Auth::wxlogin 失败时回传 wx_errcode,供客户端判断是否重试
- 登录失败自动展开手机号兜底通道

新增 tests/config_check.js:一键核对 appid 三处一致性 / 接口连通 / HTTPS 证书 / 短信开关
验证:config_check 8/8 + 163 项断言回归全通过
2026-10-28 16:25:07 +08:00

82 行
2.2 KiB
JavaScript

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

/**
* 微信登录统一入口
* 解决两个线上问题:
* 1) code 一次性(5 分钟、单次有效)——静默登录与手动登录若同时发起会互相抢 code
* → 用「单飞(in-flight)」保证同一时刻只有一个换取流程
* 2) 40029(invalid code)——可能来自 code 已被消费/过期
* → 自动用全新 code 重试一次
*/
import api from './api.js';
import { getToken, setToken, setUser } from './request.js';
let inflight = null;
/** 取微信一次性 code */
export function getWxCode() {
return new Promise((resolve, reject) => {
uni.login({
provider: 'weixin',
success: (res) => (res && res.code ? resolve(res.code) : reject(new Error('微信未返回 code'))),
fail: () => reject(new Error('未检测到微信环境,请在小程序内打开'))
});
});
}
function isCodeInvalid(err) {
const code = err && err.data ? Number(err.data.wx_errcode) : 0;
if (code === 40029 || code === 40163) return true;
return /invalid code|code been used|40029/i.test((err && err.message) || '');
}
/**
* 用 code 换 token;遇到 code 失效自动换新 code 重试一次
*/
async function exchange(payload, retry) {
const code = await getWxCode();
try {
const data = await api.wxLogin(Object.assign({}, payload, { code: code }));
setToken(data.token);
setUser(data.userinfo);
return data;
} catch (err) {
if (retry && isCodeInvalid(err)) {
return exchange(payload, false);
}
throw err;
}
}
/**
* 静默登录(进主页时调用):已登录直接返回,失败不抛错
*/
export function ensureSilentLogin() {
if (getToken()) return Promise.resolve(null);
if (inflight) return inflight;
inflight = exchange({}, true)
.catch(() => null)
.then((data) => {
inflight = null;
return data;
});
return inflight;
}
/**
* 主动授权登录(点击「微信一键登录」)
*/
export function wxAuthorizeLogin(payload) {
if (inflight) {
// 复用在途结果,避免抢同一个 code
return inflight.then((data) => {
if (data) return data;
return exchange(payload || {}, true);
});
}
inflight = exchange(payload || {}, true).then(
(data) => { inflight = null; return data; },
(err) => { inflight = null; throw err; }
);
return inflight;
}