Merge pull request #3728 from huangzhhui/pr/3727

Added support for `secret` of Apollo
This commit is contained in:
李铭昕 2021-06-23 15:18:13 +08:00 committed by GitHub
commit 830f9f57a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 10 deletions

View File

@ -52,6 +52,7 @@
- [#3698](https://github.com/hyperf/hyperf/pull/3698) Support PHP8 Attribute which can replace doctrine annotations. - [#3698](https://github.com/hyperf/hyperf/pull/3698) Support PHP8 Attribute which can replace doctrine annotations.
- [#3714](https://github.com/hyperf/hyperf/pull/3714) Added ide-helper component. - [#3714](https://github.com/hyperf/hyperf/pull/3714) Added ide-helper component.
- [#3722](https://github.com/hyperf/hyperf/pull/3722) Added config-center component. - [#3722](https://github.com/hyperf/hyperf/pull/3722) Added config-center component.
- [#3728](https://github.com/hyperf/hyperf/pull/3728) Added support for `secret` of Apollo.
## Optimized ## Optimized

View File

@ -87,6 +87,27 @@ class Client implements ClientInterface
return $this->option; return $this->option;
} }
private function hasSecret(): bool
{
return ! empty($this->option->getSecret());
}
private function getTimestamp(): string
{
[$usec, $sec] = explode(' ', microtime());
return sprintf('%.0f', (floatval($usec) + floatval($sec)) * 1000);
}
private function getAuthorization(string $timestamp, string $pathWithQuery): string
{
if (! $this->hasSecret()) {
return '';
}
$toSignature = $timestamp . "\n" . $pathWithQuery;
$signature = base64_encode(hash_hmac('sha1', $toSignature, $this->option->getSecret(), true));
return sprintf('Apollo %s:%s', $this->option->getAppid(), $signature);
}
private function coroutinePull(array $namespaces): array private function coroutinePull(array $namespaces): array
{ {
$option = $this->option; $option = $this->option;
@ -99,11 +120,19 @@ class Client implements ClientInterface
throw new RuntimeException('Invalid http client.'); throw new RuntimeException('Invalid http client.');
} }
$releaseKey = ReleaseKey::get($option->buildCacheKey($namespace), null); $releaseKey = ReleaseKey::get($option->buildCacheKey($namespace), null);
$query = [
'ip' => $option->getClientIp(),
'releaseKey' => $releaseKey,
];
$timestamp = $this->getTimestamp();
$headers = [
'Authorization' => $this->getAuthorization($timestamp, parse_url($option->buildBaseUrl(), PHP_URL_PATH) . $namespace . '?' . http_build_query($query)),
'Timestamp' => $timestamp,
];
$response = $client->get($option->buildBaseUrl() . $namespace, [ $response = $client->get($option->buildBaseUrl() . $namespace, [
'query' => [ 'query' => $query,
'ip' => $option->getClientIp(), 'headers' => $headers,
'releaseKey' => $releaseKey,
],
]); ]);
if ($response->getStatusCode() === 200 && strpos($response->getHeaderLine('Content-Type'), 'application/json') !== false) { if ($response->getStatusCode() === 200 && strpos($response->getHeaderLine('Content-Type'), 'application/json') !== false) {
$body = json_decode((string) $response->getBody(), true); $body = json_decode((string) $response->getBody(), true);
@ -132,12 +161,20 @@ class Client implements ClientInterface
if (! $client instanceof \GuzzleHttp\Client) { if (! $client instanceof \GuzzleHttp\Client) {
throw new RuntimeException('Invalid http client.'); throw new RuntimeException('Invalid http client.');
} }
$releaseKey = ReleaseKey::get($this->option->buildCacheKey($namespace), null); $releaseKey = ReleaseKey::get($this->option->buildCacheKey($namespace));
$query = [
'ip' => $this->option->getClientIp(),
'releaseKey' => $releaseKey,
];
$timestamp = $this->getTimestamp();
$headers = [
'Authorization' => $this->getAuthorization($timestamp, parse_url($url, PHP_URL_PATH) . $namespace . '?' . http_build_query($query)),
'Timestamp' => $timestamp,
];
$response = $client->get($url . $namespace, [ $response = $client->get($url . $namespace, [
'query' => [ 'query' => $query,
'ip' => $this->option->getClientIp(), 'headers' => $headers,
'releaseKey' => $releaseKey,
],
]); ]);
if ($response->getStatusCode() === 200 && strpos($response->getHeaderLine('Content-Type'), 'application/json') !== false) { if ($response->getStatusCode() === 200 && strpos($response->getHeaderLine('Content-Type'), 'application/json') !== false) {
$body = json_decode((string) $response->getBody(), true); $body = json_decode((string) $response->getBody(), true);

View File

@ -27,7 +27,8 @@ class ClientFactory
->setCluster($config->get('config_center.drivers.apollo.cluster', '')) ->setCluster($config->get('config_center.drivers.apollo.cluster', ''))
->setClientIp($config->get('config_center.drivers.apollo.client_ip', current(swoole_get_local_ip()))) ->setClientIp($config->get('config_center.drivers.apollo.client_ip', current(swoole_get_local_ip())))
->setPullTimeout($config->get('config_center.drivers.apollo.pull_timeout', 10)) ->setPullTimeout($config->get('config_center.drivers.apollo.pull_timeout', 10))
->setIntervalTimeout($config->get('config_center.drivers.apollo.interval_timeout', 60)); ->setIntervalTimeout($config->get('config_center.drivers.apollo.interval_timeout', 60))
->setSecret($config->get('config_center.drivers.apollo.secret', ''));
$namespaces = $config->get('config_center.drivers.apollo.namespaces', []); $namespaces = $config->get('config_center.drivers.apollo.namespaces', []);
$callbacks = []; $callbacks = [];
foreach ($namespaces as $namespace => $callable) { foreach ($namespaces as $namespace => $callable) {

View File

@ -50,6 +50,11 @@ class Option
*/ */
private $intervalTimeout = 60; private $intervalTimeout = 60;
/**
* @var string
*/
private $secret;
public function buildBaseUrl(): string public function buildBaseUrl(): string
{ {
return implode('/', [ return implode('/', [
@ -144,4 +149,15 @@ class Option
$this->intervalTimeout = $intervalTimeout; $this->intervalTimeout = $intervalTimeout;
return $this; return $this;
} }
public function setSecret(string $secret): self
{
$this->secret = $secret;
return $this;
}
public function getSecret(): string
{
return $this->secret;
}
} }