Skip to content

Commit

Permalink
Merge pull request #571 from epavlyuchenkov/feature/WALITE-572
Browse files Browse the repository at this point in the history
Поддержка метода получения субдомена по refresh токену
  • Loading branch information
bessudnov authored Aug 27, 2024
2 parents b9ffea2 + c103854 commit fb6f58f
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 8 deletions.
17 changes: 9 additions & 8 deletions examples/get_account_subdomain.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
5 changes: 5 additions & 0 deletions src/AmoCRM/Client/AmoCRMApiRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
}
Expand Down
93 changes: 93 additions & 0 deletions src/AmoCRM/OAuth/AmoCRMOAuth.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -40,6 +41,7 @@
use League\OAuth2\Client\Token\AccessToken;
use League\OAuth2\Client\Token\AccessTokenInterface;

use Throwable;
use function sprintf;

/**
Expand Down Expand Up @@ -396,6 +398,7 @@ public function exchangeApiKey(string $login, string $apiKey)
}

/**
* @deprecated
* Получение субдомена аккаунта по токену
*
* @param AccessTokenInterface $accessToken
Expand Down Expand Up @@ -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;
}

/**
* Расшифровывает полученный одноразовый токен и возвращает модель
*
Expand Down Expand Up @@ -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;
}
}

0 comments on commit fb6f58f

Please sign in to comment.