73 lines
2.3 KiB
PHP
73 lines
2.3 KiB
PHP
<?php
|
||
|
||
namespace App\Services;
|
||
|
||
use App\Exceptions\RepositoryException;
|
||
use Illuminate\Support\Facades\Http;
|
||
use Illuminate\Support\Facades\Log;
|
||
|
||
/**
|
||
* 微信小程序服务(wx.login 登录凭证校验 code2session)
|
||
*
|
||
* 在线支付前置:用小程序 wx.login() 返回的 code 换取付款人 openid,
|
||
* 作为旺铺统一下单的 open_id(服务商模式下的微信用户标识)。
|
||
*/
|
||
class WechatMiniService
|
||
{
|
||
/**
|
||
* wx.login 的 code 换 openid
|
||
*
|
||
* @return string 用户 openid
|
||
* @throws RepositoryException 未配置小程序或凭证校验失败
|
||
*/
|
||
public function code2session(string $code): string
|
||
{
|
||
$appid = $this->appid();
|
||
$secret = $this->config('mini_secret');
|
||
if ($appid === '' || $secret === '') {
|
||
throw new RepositoryException('微信小程序未配置 AppID/Secret,请联系管理员');
|
||
}
|
||
|
||
$result = Http::timeout(10)->withOptions([
|
||
'verify' => false, // 禁用 SSL 证书验证
|
||
])->get('https://api.weixin.qq.com/sns/jscode2session', [
|
||
'appid' => $appid,
|
||
'secret' => $secret,
|
||
'js_code' => $code,
|
||
'grant_type' => 'authorization_code',
|
||
])->json();
|
||
|
||
$openid = is_array($result) ? (string) ($result['openid'] ?? '') : '';
|
||
if ($openid === '') {
|
||
Log::warning('微信 code2session 失败', ['response' => $result]);
|
||
throw new RepositoryException('微信登录凭证校验失败:' . ($result['errmsg'] ?? '请重新进入小程序'));
|
||
}
|
||
|
||
return $openid;
|
||
}
|
||
|
||
/**
|
||
* 小程序 AppID(在线支付下单 appid 兜底等场景复用)
|
||
*/
|
||
public function appid(): string
|
||
{
|
||
return $this->config('mini_appid');
|
||
}
|
||
|
||
/**
|
||
* 读取应用配置:后台站点配置(微信应用配置分组)优先,为空回退 config/services.php(env)
|
||
*/
|
||
protected function config(string $key): string
|
||
{
|
||
$value = site_config('wechat.' . $key, '');
|
||
if ($value === null || $value === '') {
|
||
$value = match ($key) {
|
||
'mini_appid' => config('services.wechat.mini.appid', ''),
|
||
'mini_secret' => config('services.wechat.mini.secret', ''),
|
||
default => '',
|
||
};
|
||
}
|
||
return trim((string) $value);
|
||
}
|
||
}
|