From 51ae428999d10b1f94483a7c869af694004630b5 Mon Sep 17 00:00:00 2001 From: epavlyuchenkov Date: Wed, 21 Aug 2024 18:28:02 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA=D1=83=20?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B0=20=D0=BF=D0=BE=D0=BB=D1=83?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=81=D1=83=D0=B1=D0=B4=D0=BE?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B0=20=D0=BF=D0=BE=20refresh=20=D1=82?= =?UTF-8?q?=D0=BE=D0=BA=D0=B5=D0=BD=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/get_account_subdomain.php | 16 ++--- src/AmoCRM/Client/AmoCRMApiRequest.php | 5 ++ src/AmoCRM/OAuth/AmoCRMOAuth.php | 93 ++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 8 deletions(-) diff --git a/examples/get_account_subdomain.php b/examples/get_account_subdomain.php index 00c9023d..5c3c211d 100644 --- a/examples/get_account_subdomain.php +++ b/examples/get_account_subdomain.php @@ -8,24 +8,24 @@ try { /** - * В случае потери/смены субдомена аккаунта, мы можем его получить с помощью access_token - * Сделав запрос на www.amocrm.ru/oauth2/account/subdomain + * В случае потери/смены субдомена аккаунта, мы можем его получить с помощью refresh_token + * Сделав запрос на api-{a|b}.amocrm.ru/oauth2/account/current/subdomain * - * Получим модель с информацией о домене аккаунта по access_token + * Получим модель с информацией о домене аккаунта по refresh_token * Подробнее: @see AccountDomainModel * - * Запрос уходит на www.amocrm.ru/oauth2/account/subdomain - * С Authorization: Bearer {access_token} + * Запрос уходит на api-{a|b}.amocrm.ru/oauth2/account/current/subdomain + * С X-Refresh-Token: {refresh_token} * - * @example curl 'https://www.amocrm.ru/oauth2/account/subdomain' -H 'Authorization: Bearer {access_token}' + * @example curl 'https://api-a.amocrm.ru/oauth2/account/current/subdomain' -H 'X-Refresh-Token: {refresh_token}' */ $accountDomainModel = $apiClient->getOAuthClient() - ->getAccountDomain($accessToken); + ->getAccountDomainByRefreshToken($accessToken); var_dump($accountDomainModel->toArray()); // Возьмём из полученной модели текущий subdomain аккаунта и засетим наш субдомен аккаунта в апи клиенте - $apiClient->setAccountBaseDomain($accountDomainModel->getSubdomain()); + $apiClient->setAccountBaseDomain($accountDomainModel->getDomain()); var_dump($apiClient->getAccountBaseDomain()); } catch (AmoCRMApiException $e) { diff --git a/src/AmoCRM/Client/AmoCRMApiRequest.php b/src/AmoCRM/Client/AmoCRMApiRequest.php index be572098..ad12bda0 100644 --- a/src/AmoCRM/Client/AmoCRMApiRequest.php +++ b/src/AmoCRM/Client/AmoCRMApiRequest.php @@ -137,6 +137,11 @@ public function __construct( $this->contextUserId = $contextUserId; $this->userAgent = $userAgent; $this->refreshAccessTokenCallback = function () { + $accountDomainModel = $this->oAuthClient->getAccountDomainByRefreshToken($this->accessToken); + + $oAuthProvider = $this->oAuthClient->getOAuthProvider(); + $this->setRequestDomain($oAuthProvider->getProtocol() . $accountDomainModel->getDomain()); + return $this->oAuthClient->getAccessTokenByRefreshToken($this->accessToken); }; } diff --git a/src/AmoCRM/OAuth/AmoCRMOAuth.php b/src/AmoCRM/OAuth/AmoCRMOAuth.php index 2a60ff80..8d704efc 100755 --- a/src/AmoCRM/OAuth/AmoCRMOAuth.php +++ b/src/AmoCRM/OAuth/AmoCRMOAuth.php @@ -5,6 +5,7 @@ use AmoCRM\Exceptions\DisposableTokenExpiredException; use AmoCRM\Exceptions\DisposableTokenInvalidDestinationException; use AmoCRM\Exceptions\DisposableTokenVerificationFailedException; +use AmoCRM\Exceptions\InvalidArgumentException; use AmoCRM\Models\AccountDomainModel; use AmoCRM\Models\BotDisposableTokenModel; use AmoCRM\Models\DisposableTokenModel; @@ -40,6 +41,7 @@ use League\OAuth2\Client\Token\AccessToken; use League\OAuth2\Client\Token\AccessTokenInterface; +use Throwable; use function sprintf; /** @@ -396,6 +398,7 @@ public function exchangeApiKey(string $login, string $apiKey) } /** + * @deprecated * Получение субдомена аккаунта по токену * * @param AccessTokenInterface $accessToken @@ -446,6 +449,60 @@ public function getAccountDomain(AccessTokenInterface $accessToken): AccountDoma return $accountDomainModel; } + /** + * Получение субдомена аккаунта по рефреш токену + * + * @param AccessTokenInterface $accessToken + * + * @return AccountDomainModel + * @throws AmoCRMApiConnectExceptionException + * @throws AmoCRMApiErrorResponseException + * @throws AmoCRMApiHttpClientException + * @throws InvalidArgumentException + */ + public function getAccountDomainByRefreshToken(AccessTokenInterface $accessToken): AccountDomainModel + { + $sharedApiDomain = $this->getSharedApiDomain($accessToken); + + try { + $response = $this->oauthProvider->getHttpClient()->request( + AmoCRMApiRequest::GET_REQUEST, + sprintf( + '%s%s%s', + $this->oauthProvider->getProtocol(), + $sharedApiDomain, + '/oauth2/account/current/subdomain' + ), + [ + 'headers' => ['X-Refresh-Token' => $accessToken->getRefreshToken()], + 'connect_timeout' => AmoCRMApiRequest::CONNECT_TIMEOUT, + 'http_errors' => false, + 'timeout' => self::REQUEST_TIMEOUT, + 'query' => [], + 'json' => [], + ] + ); + + $responseBody = (string)$response->getBody(); + if ($response->getStatusCode() !== StatusCodeInterface::STATUS_OK) { + throw new AmoCRMApiErrorResponseException( + 'Invalid response', + $response->getStatusCode(), + [], + $responseBody + ); + } + $response = json_decode($responseBody, true); + $accountDomainModel = AccountDomainModel::fromArray($response); + } catch (ConnectException $e) { + throw new AmoCRMApiConnectExceptionException($e->getMessage(), $e->getCode()); + } catch (GuzzleException $e) { + throw new AmoCRMApiHttpClientException($e->getMessage(), $e->getCode()); + } + + return $accountDomainModel; + } + /** * Расшифровывает полученный одноразовый токен и возвращает модель * @@ -549,4 +606,40 @@ public function parseBotDisposableToken(string $token, string $receiverPath = nu return BotDisposableTokenModel::fromJwtToken($jwtToken); } + + /** + * Получает домен для общих api методов из access токена, домен присутствует в токенах выписанных после 21.08.2024 + * + * @param AccessTokenInterface $accessToken + * @return string + * + * @throws InvalidArgumentException + */ + private function getSharedApiDomain(AccessTokenInterface $accessToken): string + { + try { + $parsedToken = Configuration::forUnsecuredSigner()->parser()->parse($accessToken->getToken()); + } catch (Throwable $e) { + throw new InvalidArgumentException( + 'Error parsing given access token. Prev error: ' . $e->getMessage(), + 0, + [], + 'Check access token.' + ); + } + + $claims = $parsedToken->claims(); + $apiDomain = $claims->get('api_domain', ''); + + if (empty($apiDomain)) { + throw new InvalidArgumentException( + 'Token does not contain shared api domain.', + 0, + [], + 'Update your access token.' + ); + } + + return $apiDomain; + } } From c1038547e12d923ad2c4b5afd2c8591a2a2d148d Mon Sep 17 00:00:00 2001 From: epavlyuchenkov Date: Mon, 26 Aug 2024 15:15:40 +0300 Subject: [PATCH 2/2] =?UTF-8?q?=D0=BF=D0=BE=D0=BC=D0=B5=D0=BD=D1=8F=D0=BB?= =?UTF-8?q?=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B2=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/get_account_subdomain.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/get_account_subdomain.php b/examples/get_account_subdomain.php index 5c3c211d..8eaa07b4 100644 --- a/examples/get_account_subdomain.php +++ b/examples/get_account_subdomain.php @@ -9,12 +9,13 @@ try { /** * В случае потери/смены субдомена аккаунта, мы можем его получить с помощью refresh_token - * Сделав запрос на api-{a|b}.amocrm.ru/oauth2/account/current/subdomain + * api_domain - Claim из access_token + * Сделав запрос на {api_domain}.amocrm.ru/oauth2/account/current/subdomain * * Получим модель с информацией о домене аккаунта по refresh_token * Подробнее: @see AccountDomainModel * - * Запрос уходит на api-{a|b}.amocrm.ru/oauth2/account/current/subdomain + * Запрос уходит на {api_domain}.amocrm.ru/oauth2/account/current/subdomain * С X-Refresh-Token: {refresh_token} * * @example curl 'https://api-a.amocrm.ru/oauth2/account/current/subdomain' -H 'X-Refresh-Token: {refresh_token}'