Files
esun3d/app/code/Esun/MultiLocaleTranslation/Model/Google/AccessToken.php
T
2026-09-15 10:35:56 +08:00

97 lines
3.4 KiB
PHP

<?php
declare(strict_types=1);
namespace Esun\MultiLocaleTranslation\Model\Google;
use Magento\Framework\App\CacheInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\HTTP\Client\CurlFactory;
class AccessToken
{
private const TOKEN_URL = 'https://oauth2.googleapis.com/token';
private const SCOPE = 'https://www.googleapis.com/auth/cloud-translation';
private const CACHE_PREFIX = 'ESUN_GOOGLE_TRANSLATION_TOKEN_';
public function __construct(
private readonly Credentials $credentials,
private readonly CurlFactory $curlFactory,
private readonly CacheInterface $cache
) {
}
public function get(): string
{
$credentials = $this->credentials->get();
$cacheKey = self::CACHE_PREFIX . strtoupper(hash('sha256', $credentials['client_email']));
$cached = (string)$this->cache->load($cacheKey);
if ($cached !== '') {
return $cached;
}
$now = time();
$header = ['alg' => 'RS256', 'typ' => 'JWT'];
if (!empty($credentials['private_key_id'])) {
$header['kid'] = $credentials['private_key_id'];
}
$claims = [
'iss' => $credentials['client_email'],
'scope' => self::SCOPE,
'aud' => self::TOKEN_URL,
'iat' => $now,
'exp' => $now + 3600,
];
$unsignedJwt = $this->base64UrlEncode($this->encodeJson($header))
. '.' . $this->base64UrlEncode($this->encodeJson($claims));
$privateKey = openssl_pkey_get_private($credentials['private_key']);
$signature = '';
if ($privateKey === false
|| !openssl_sign($unsignedJwt, $signature, $privateKey, OPENSSL_ALGO_SHA256)
) {
throw new LocalizedException(__('Unable to sign the Google service account request.'));
}
$assertion = $unsignedJwt . '.' . $this->base64UrlEncode($signature);
$client = $this->curlFactory->create();
$client->setTimeout(30);
$client->setHeaders(['Content-Type' => 'application/x-www-form-urlencoded']);
$client->post(self::TOKEN_URL, http_build_query([
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion' => $assertion,
], '', '&', PHP_QUERY_RFC3986));
$response = json_decode((string)$client->getBody(), true);
$token = is_array($response) ? (string)($response['access_token'] ?? '') : '';
if ($client->getStatus() < 200 || $client->getStatus() >= 300 || $token === '') {
$message = is_array($response)
? (string)($response['error_description'] ?? $response['error'] ?? '')
: '';
throw new LocalizedException(
__('Google service account authentication failed (HTTP %1): %2',
$client->getStatus(),
$message ?: 'Unknown error')
);
}
$lifetime = max(60, min(3300, (int)($response['expires_in'] ?? 3600) - 300));
$this->cache->save($token, $cacheKey, [], $lifetime);
return $token;
}
private function base64UrlEncode(string $value): string
{
return rtrim(strtr(base64_encode($value), '+/', '-_'), '=');
}
private function encodeJson(array $value): string
{
return json_encode(
$value,
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR
);
}
}