<?php declare(strict_types=1); namespace App\Utils; use App\Dictionary\WeChat\Official\OpenApi; use EasyWeChat\Kernel\Contracts\RefreshableAccessToken; use HttpException; use Illuminate\Support\Facades\Redis; use JsonException; use JetBrains\PhpStorm\ArrayShape; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; use Symfony\Component\HttpClient\HttpClient; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; class CentralControlAccessToken implements RefreshableAccessToken { public function __construct(){} /** * Access Token Save Key. * * @return string */ public function getKey(): string { return 'mini_platform:access_token'; } /** * Get Access Token. * * @return string * * @throws ClientExceptionInterface * @throws ContainerExceptionInterface * @throws DecodingExceptionInterface * @throws HttpException * @throws JsonException * @throws NotFoundExceptionInterface * @throws RedirectionExceptionInterface * @throws ServerExceptionInterface * @throws TransportExceptionInterface */ public function getToken(): string { $token = Redis::get($this->getKey()); if ($token && is_string($token)) { return $token; } return $this->refresh(); } /** * Get Access Token For Query Params. * * @return array<string, string> * * @throws ClientExceptionInterface * @throws ContainerExceptionInterface * @throws DecodingExceptionInterface * @throws HttpException * @throws JsonException * @throws NotFoundExceptionInterface * @throws RedirectionExceptionInterface * @throws ServerExceptionInterface * @throws TransportExceptionInterface */ #[ArrayShape(['access_token' => "string"])] public function toQuery(): array { return ['access_token' => $this->getToken()]; } /** * @return string * * @throws HttpException * @throws JsonException * @throws ClientExceptionInterface * @throws DecodingExceptionInterface * @throws RedirectionExceptionInterface * @throws ServerExceptionInterface * @throws TransportExceptionInterface */ public function refresh(): string { $client = HttpClient::create(['base_uri' => 'https://api.weixin.qq.com/']); $response = $client->request( 'GET', OpenApi::GET_ACCESS_TOKEN->value, [ 'query' => [ 'grant_type' => 'client_credential', 'appid' => config('wechat.mini.app_id'), 'secret' =>config('wechat.mini.secret'), ], ] )->toArray(false); if (empty($response['access_token'])) { throw new HttpException('Failed to get access_token: '. json_encode($response, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE) ); } Redis::setex($this->getKey(), (int)$response['expires_in'] - 300, $response['access_token']); return $response['access_token']; } }