diff --git a/examples/get_account_subdomain.php b/examples/get_account_subdomain.php index 00c9023..8eaa07b 100644 --- a/examples/get_account_subdomain.php +++ b/examples/get_account_subdomain.php @@ -8,24 +8,25 @@ try { /** - * В случае потери/смены субдомена аккаунта, мы можем его получить с помощью access_token - * Сделав запрос на www.amocrm.ru/oauth2/account/subdomain + * В случае потери/смены субдомена аккаунта, мы можем его получить с помощью refresh_token + * api_domain - Claim из access_token + * Сделав запрос на {api_domain}.amocrm.ru/oauth2/account/current/subdomain * - * Получим модель с информацией о домене аккаунта по access_token + * Получим модель с информацией о домене аккаунта по refresh_token * Подробнее: @see AccountDomainModel * - * Запрос уходит на www.amocrm.ru/oauth2/account/subdomain - * С Authorization: Bearer {access_token} + * Запрос уходит на {api_domain}.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 be57209..ad12bda 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 2a60ff8..8d704ef 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; + } }