| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 |
- <?php
- declare(strict_types=1);
- namespace app\miniapi\auth;
- use app\miniapi\exception\ApiException;
- use support\Log;
- final class WechatIdentityProvider implements IdentityProvider
- {
- public function exchange(string $code): array
- {
- $appid = (string) config('mini_api.wechat_appid', '');
- $secret = (string) config('mini_api.wechat_secret', '');
- if ($appid === '' || $secret === '') {
- throw new ApiException(50301, '微信登录尚未配置', 503);
- }
- $url = 'https://api.weixin.qq.com/sns/jscode2session?' . http_build_query([
- 'appid' => $appid,
- 'secret' => $secret,
- 'js_code' => $code,
- 'grant_type' => 'authorization_code',
- ]);
- $ch = curl_init($url);
- curl_setopt_array($ch, [
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_CONNECTTIMEOUT => 5,
- CURLOPT_TIMEOUT => 10,
- CURLOPT_SSL_VERIFYPEER => true,
- CURLOPT_SSL_VERIFYHOST => 2,
- CURLOPT_FOLLOWLOCATION => false,
- ]);
- $raw = curl_exec($ch);
- $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- curl_close($ch);
- if ($raw === false || $status !== 200) {
- throw new ApiException(50302, '微信登录服务暂时不可用', 503);
- }
- $data = json_decode($raw, true);
- if (!is_array($data)) {
- throw new ApiException(50302, '微信登录服务暂时不可用', 503);
- }
- $openid = $data['openid'] ?? null;
- if (!is_string($openid) || $openid === '' || strlen($openid) > 128) {
- throw $this->failure((int) ($data['errcode'] ?? 0));
- }
- // session_key and unionid are deliberately neither returned nor logged.
- return [
- 'appid' => $appid,
- 'openid' => $openid,
- ];
- }
- /**
- * WeChat reports credential problems with HTTP 200 plus errcode, so an expired code, a
- * reused code and an over-quota app would otherwise all collapse into one message and
- * leave nothing to search for in the logs.
- */
- private function failure(int $errcode): ApiException
- {
- Log::warning('mini_api.wechat_login', ['errcode' => $errcode]);
- return match ($errcode) {
- 40029, 40163 => new ApiException(40102, '微信登录凭据已失效,请重新登录', 401),
- 40226, 45009, 45011 => new ApiException(42901, '微信登录请求过于频繁,请稍后再试', 429, ['retry_after' => 60]),
- 40013, 40125 => new ApiException(50301, '微信登录配置无效,请联系平台管理员', 503),
- default => new ApiException(40102, '微信登录凭据无效,请重新登录', 401),
- };
- }
- }
|