Google API Client "токен обновления должен быть передан или установлен как часть setAccessToken"
в настоящее время я сталкиваюсь с очень странной проблемой, действительно, я следовал этому же руководству (https://developers.google.com/google-apps/calendar/quickstart/php) из документации Google API. Я попробовал его дважды, в первый раз он работает как шарм, но после истечения срока действия маркера доступа скрипт, предоставленный прямо Google API Doc, не смог его обновить.
TL; DR
вот сообщение об ошибке:
sam@ssh:~$ php www/path/to/app/public/quickstart.php
Fatal error: Uncaught exception 'LogicException' with message 'refresh token must be passed in or set as part of setAccessToken' in /home/pueblo/www/path/to/app/vendor/google/apiclient/src/Google/Client.php:258
Stack trace:
#0 /home/pueblo/www/path/to/app/public/quickstart.php(55): Google_Client->fetchAccessTokenWithRefreshToken(NULL)
#1 /home/pueblo/www/path/to/app/public/quickstart.php(76): getClient()
#2 {main}
thrown in /home/pueblo/www/path/to/app/vendor/google/apiclient/src/Google/Client.php on line 258
здесь часть PHP скрипта от google я изменил:
require_once __DIR__ . '/../vendor/autoload.php';
// I don't want the creds to be in my home folder, I prefer them in the app's root
define('APPLICATION_NAME', 'LRS API Calendar');
define('CREDENTIALS_PATH', __DIR__ . '/../.credentials/calendar-php-quickstart.json');
define('CLIENT_SECRET_PATH', __DIR__ . '/../client_secret.json');
Я также изменил expandHomeDirectory
поэтому я мог бы "отключить" его, не изменяя слишком много кода:
function expandHomeDirectory($path) {
$homeDirectory = getenv('HOME');
if (empty($homeDirectory)) {
$homeDirectory = getenv('HOMEDRIVE') . getenv('HOMEPATH');
}
return $path;
// return str_replace('~', realpath($homeDirectory), $path);
}
поэтому, чтобы проверить, был ли я неправ или если Google был, я сделал эксперимент: вчера вечером я запускаю сценарий quickstart из ssh, чтобы проверить, работает ли он, и действительно это было, поэтому я решил проверить сегодня утром, если он все еще работает так же, как это было до того, как я спал, и это не так, я думаю, что что-то не так с Google quickstart.php
.
Я надеюсь, что кто-то может мне помочь, я уже проверил все другие сообщения по этому вопросу, но они все устарели.
9 ответов
недавно у меня была такая же проблема, и я решил ее с помощью этого.
<?php
$client->setRedirectUri($this->_redirectURI);
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
объясняю ..... Токен обновления не возвращается, потому что мы не принудительно approvalPrompt. Автономного режима недостаточно. Мы должны заставить approvalPrompt. Кроме того, перед этими двумя вариантами необходимо установить redirectURI. У меня получилось.
Это моя полная функция
<?php
private function getClient()
{
$client = new Google_Client();
$client->setApplicationName($this->projectName);
$client->setScopes(SCOPES);
$client->setAuthConfig($this->jsonKeyFilePath);
$client->setRedirectUri($this->redirectUri);
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
// Load previously authorized credentials from a file.
if (file_exists($this->tokenFile)) {
$accessToken = json_decode(file_get_contents($this->tokenFile),
true);
} else {
// Request authorization from the user.
$authUrl = $client->createAuthUrl();
header('Location: ' . filter_var($authUrl, FILTER_SANITIZE_URL));
if (isset($_GET['code'])) {
$authCode = $_GET['code'];
// Exchange authorization code for an access token.
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
header('Location: ' . filter_var($this->redirectUri,
FILTER_SANITIZE_URL));
if(!file_exists(dirname($this->tokenFile))) {
mkdir(dirname($this->tokenFile), 0700, true);
}
file_put_contents($this->tokenFile, json_encode($accessToken));
}else{
exit('No code found');
}
}
$client->setAccessToken($accessToken);
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
// save refresh token to some variable
$refreshTokenSaved = $client->getRefreshToken();
// update access token
$client->fetchAccessTokenWithRefreshToken($refreshTokenSaved);
// pass access token to some variable
$accessTokenUpdated = $client->getAccessToken();
// append refresh token
$accessTokenUpdated['refresh_token'] = $refreshTokenSaved;
//Set the new acces token
$accessToken = $refreshTokenSaved;
$client->setAccessToken($accessToken);
// save to file
file_put_contents($this->tokenFile,
json_encode($accessTokenUpdated));
}
return $client;
}
я столкнулся с той же проблемой с новой библиотекой Google api. Поиск решения привел следующую ссылку: RefreshToken не получает отправить обратно после того, как я получу новый маркер google sheets API
основываясь на этой информации, я изменил часть кода quickstart в соответствии с моими потребностями. После первой авторизации в Google я получил drive-php-quickstart.json, который содержит refresh_token, который истекает через 3600 секунд или один час. Маркер обновления выдается только один раз, поэтому, если он потерян, требуется повторная авторизация. Итак, чтобы иметь его всегда в drive-php-quickstart.json я сделал следующее:
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
// save refresh token to some variable
$refreshTokenSaved = $client->getRefreshToken();
// update access token
$client->fetchAccessTokenWithRefreshToken($refreshTokenSaved);
// pass access token to some variable
$accessTokenUpdated = $client->getAccessToken();
// append refresh token
$accessTokenUpdated['refresh_token'] = $refreshTokenSaved;
// save to file
file_put_contents($credentialsPath, json_encode($accessTokenUpdated));
}
мой совет -сохранить токен обновления .json сразу после получения маркера доступа и если токен доступа истек, используйте токен обновления.
в моих проектах работают следующим образом:
public static function getClient()
{
$client = new Google_Client();
$client->setApplicationName('JhvInformationTable');
$client->setScopes(Google_Service_Calendar::CALENDAR_READONLY);
$client->setAuthConfig('credentials.json');
$client->setAccessType('offline');
// Load previously authorized credentials from a file.
$credentialsPath = 'token.json';
$credentialsPath2 = 'refreshToken.json';
if (file_exists($credentialsPath)) {
$accessToken = json_decode(file_get_contents($credentialsPath), true);
} else {
// Request authorization from the user.
$authUrl = $client->createAuthUrl();
//printf("Open the following link in your browser:\n%s\n", $authUrl);
//print 'Enter verification code: ';
$authCode = trim(fgets(STDIN));
//echo "<script> location.href='".$authUrl."'; </script>";
//exit;
$authCode ='********To get code, please uncomment the code above********';
// Exchange authorization code for an access token.
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
$refreshToken = $client->getRefreshToken();
// Check to see if there was an error.
if (array_key_exists('error', $accessToken)) {
throw new Exception(join(', ', $accessToken));
}
// Store the credentials to disk.
if (!file_exists(dirname($credentialsPath))) {
mkdir(dirname($credentialsPath), 0700, true);
}
file_put_contents($credentialsPath, json_encode($accessToken));
file_put_contents($credentialsPath2, json_encode($refreshToken));
printf("Credentials saved to %s\n", $credentialsPath);
}
$client->setAccessToken($accessToken);
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$refreshToken = json_decode(file_get_contents($credentialsPath2), true);
$client->fetchAccessTokenWithRefreshToken($refreshToken);
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
return $client;
}
просто некоторое обновление для тех, у кого возникли проблемы с этим сообщением, в основном потому, что только первая команда fetchAccessTokenWithAuthCode() генерирует учетные данные, содержащие токен обновления (технически навсегда действительный - нет 2 часов действия, если вы его не отмените). Когда вы получаете новый, он заменяет исходный, но не содержит токен обновления, который ему нужен, поэтому в следующий раз, когда вам нужно обновить токен, он аварийно завершит работу. Это можно легко исправить, заменив функцию обновления к примеру это:
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$oldAccessToken=$client->getAccessToken();
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$accessToken=$client->getAccessToken();
$accessToken['refresh_token']=$oldAccessToken['refresh_token'];
file_put_contents($credentialsPath, json_encode($accessToken));
}
теперь каждый раз, когда вы обновить маркер доступа, маркер обновления тоже передается.
у меня были те же проблемы и, наконец, пойти на работу:
Предыстория:
Я получил ту же ошибку. Вот что я нашел:
эта ошибка:
PHP фатальная ошибка: Uncaught LogicException: токен обновления должен быть передан или установлен как часть setAccessToken in / Library/WebServer/документы/сайты/тест/скрипты/поставщик/google/apiclient/src/Google / клиент.php: 267
ссылается на обновить маркер доступа (aka Refresh) метод:
$client->fetchAccessTokenWithRefreshToken($refreshTokenSaved);
почему это не удается? Короче говоря, я понял, когда я распечатал массив $ accessToken, который происходит от декодирования этого файла json (за быстрый код, который вы опубликовали/который приходит из google)
учетные данные / календарь-php-quickstart.в JSON
Я нашел ошибку из-за того, как массив accessToken печатается, когда я print_r:
массив ( [способом] => Массив ( [способом] => xyz123 [token_type] => на предъявителя [expires_in] => 3600 [маркер обновления] => xsss112222 [создал] => 1511379484 )
)
устранение:
$refreshToken = $accessToken ["access_token"] ["refresh_token"];
прямо перед этой строкой:
$client->fetchAccessTokenWithRefreshToken($refreshToken);
Я МОГУ, наконец, обновить токен по мере необходимости, когда он истекает через час. Я думаю, разработчики этой статьи предположили, что массив печатает как:
массив ( [способом] => xyz123 [token_type] => на предъявителя [expires_in] => 3600 [маркер обновления] => xsss112222 [создал] => 1511379484 )
поэтому они думали, что вы можете просто сделать $accessToken["refresh_token"]; это неправильно.
теперь у нас есть допустимое значение для $refreshToken, поэтому ошибка должна уйти если ты сделаешь это. Я также обновил автора по ссылке обратной связи, чтобы сообщить им об этом, если другие разработчики php столкнутся с этой проблемой. Надеюсь, это кому-то поможет. Мои извинения, если я отформатировал этот пост плохо, я новичок в S. E. я просто хотел поделиться, поскольку я, наконец, получил это на работу.
вам нужно сериализовать accestoken
когда вы пишете это в credentialsPath
.
// Exchange authorization code for an access token.
$accessToken = $client->authenticate($authCode);
// Store the credentials to disk.
if(!file_exists(dirname($credentialsPath))) {
mkdir(dirname($credentialsPath), 0700, true);
}
$serArray = serialize($accessToken);
file_put_contents($credentialsPath, $serArray);
printf("Credentials saved to %s\n", $credentialsPath);
и когда вы читаете из файла, вы должны восстановить его.
if (file_exists($credentialsPath)) {
$unserArray = file_get_contents($credentialsPath);
$accessToken = unserialize($unserArray);
}
полная функция
function getClient() {
$client = new Google_Client();
// Set to name/location of your client_secrets.json file.
$client->setAuthConfigFile('client_secret.json');
// Set to valid redirect URI for your project.
$client->setRedirectUri('http://localhost');
$client->setApprovalPrompt('force');
$client->addScope(Google_Service_YouTube::YOUTUBE_READONLY);
$client->setAccessType('offline');
// Load previously authorized credentials from a file.
$credentialsPath = expandHomeDirectory(CREDENTIALS_PATH);
if (file_exists($credentialsPath)) {
$unserArray = file_get_contents($credentialsPath);
$accessToken = unserialize($unserArray);
} else {
// Request authorization from the user.
$authUrl = $client->createAuthUrl();
printf("Open the following link in your browser:\n%s\n", $authUrl);
print 'Enter verification code: ';
$authCode = trim(fgets(STDIN));
// Exchange authorization code for an access token.
$accessToken = $client->authenticate($authCode);
// Store the credentials to disk.
if(!file_exists(dirname($credentialsPath))) {
mkdir(dirname($credentialsPath), 0700, true);
}
$serArray = serialize($accessToken);
file_put_contents($credentialsPath, $serArray);
printf("Credentials saved to %s\n", $credentialsPath);
}
$client->setAccessToken($accessToken);
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->refreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, $client->getAccessToken());
}
return $client;
}
Google обновил свои PHP Quickstart, с улучшенным методом для обработки этого:
фрагмент ниже:
// Exchange authorization code for an access token.
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
$client->setAccessToken($accessToken);
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
в моем случае я забыл установить тип доступа как "автономно", без которой маркер не вырабатывается.
$client->setAccessType('offline');
Как только это будет сделано, образец кода, приведенный в документации google, будет работать.
// Exchange authorization code for an access token.
// "refresh_token" is returned along with the access token
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
$client->setAccessToken($accessToken);
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
поэтому через некоторое время vieweing этот код:
// Exchange authorization code for an access token.
// "refresh_token" is returned along with the access token
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
$client->setAccessToken($accessToken);
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
все, что необходимо это менять:
// Exchange authorization code for an access token.
// "refresh_token" is returned along with the access token
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
$client->setAccessToken($accessToken);
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($accessToken);
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
поскольку эта функция $client - >getRefreshToken () возвращает null, и если вы предоставите $accessToken напрямую, он будет работать нормально и обновлять ваш файл, надеюсь, что он решит проблему.