current(); if (($app['app_id'] ?? '') === '' || ($app['app_secret'] ?? '') === '') { UtilsService::getInstance()->errorThrow('小程序 AppID/AppSecret 未配置'); } $result = Http::asJson()->get($this->baseUrl . 'sns/jscode2session', [ 'appid' => $app['app_id'], 'secret' => $app['app_secret'], 'js_code' => $code, 'grant_type' => 'authorization_code', ])->json(); if (!empty($result['errcode'])) { UtilsService::getInstance()->errorThrow('微信登录失败:' . ($result['errmsg'] ?? '未知错误')); } if (empty($result['openid'])) { UtilsService::getInstance()->errorThrow('微信登录失败:未拿到 openid'); } $result['app_code'] = (string) ($app['code'] ?? ''); return $result; } /** * 手机号快速验证:前端拿到的 code 换真实号码 */ public function getPhoneNumber(string $phoneCode): string { $token = $this->accessToken(); $result = Http::asJson()->post( $this->baseUrl . 'wxa/business/getuserphonenumber?access_token=' . $token, ['code' => $phoneCode] )->json(); if (!empty($result['errcode'])) { UtilsService::getInstance()->errorThrow('获取手机号失败:' . ($result['errmsg'] ?? '未知错误')); } return (string) ($result['phone_info']['phoneNumber'] ?? ''); } /** * 接口调用凭证,按 appid 缓存 */ public function accessToken(): string { $app = WxAppService::getInstance()->current(); $redis = RedisService::getInstance()->init(config('nl.redis.wechat_token')); $cached = $redis->get($app['app_id']); if (!empty($cached)) { return (string) $cached; } $result = Http::asJson()->get($this->baseUrl . 'cgi-bin/token', [ 'grant_type' => 'client_credential', 'appid' => $app['app_id'], 'secret' => $app['app_secret'], ])->json(); if (empty($result['access_token'])) { UtilsService::getInstance()->errorThrow('获取 access_token 失败:' . ($result['errmsg'] ?? '未知错误')); } // 提前 300 秒过期,避免临界点上拿到即将失效的 token $redis->set($app['app_id'], $result['access_token'], max(60, (int) ($result['expires_in'] ?? 7200) - 300)); return (string) $result['access_token']; } }