web-dev-qa-db-de.com

Google API-Client "Aktualisierungstoken muss in setAccessToken übergeben oder festgelegt werden"

Ich bin derzeit mit einem sehr seltsamen Problem konfrontiert. In der Tat habe ich genau diesen Leitfaden ( https://developers.google.com/google-apps/calendar/quickstart/php ) aus der Google API-Dokumentation befolgt. Ich habe es zweimal versucht, beim ersten Mal funktioniert es wie ein Zauber, aber nach Ablauf des Zugriffstokens konnte das von Google API direkt bereitgestellte Skript nicht aktualisiert werden.

TL; DR

Hier ist die Fehlermeldung:

[email protected]:~$ 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

Hier ist der Teil des PHP-Skripts von Google, das ich geändert habe:

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');

Ich habe auch expandHomeDirectory geändert, um ihn "deaktivieren" zu können, ohne zu viel Code zu ändern:

function expandHomeDirectory($path) {
  $homeDirectory = getenv('HOME');
  if (empty($homeDirectory)) {
    $homeDirectory = getenv('HOMEDRIVE') . getenv('HOMEPATH');
  }
  return $path;
  // return str_replace('~', realpath($homeDirectory), $path);
}

Um zu überprüfen, ob ich mich geirrt habe oder ob Google es war, habe ich ein Experiment durchgeführt: Gestern Abend starte ich das Schnellstart-Skript von ssh, um zu überprüfen, ob es funktioniert, und tatsächlich war es das. Also habe ich mich heute morgen entschieden, ob es noch funktioniert Wie es vor dem Schlafen war und es nicht so war, denke ich, ist mit dem quickstart.php von Google etwas nicht in Ordnung.

Ich hoffe jemand kann mir helfen, ich habe bereits alle anderen Beiträge zu diesem Thema geprüft, aber sie sind alle veraltet.

12
Sam

Ich habe vor kurzem das gleiche Problem und habe es damit gelöst.

<?php
 $client->setRedirectUri($this->_redirectURI);
 $client->setAccessType('offline');
 $client->setApprovalPrompt('force');

Ich erkläre das ..... Das Refresh-Token wird nicht zurückgegeben, weil wir das Genehmigungszeichen nicht erzwungen haben. Der Offline-Modus ist nicht ausreichend. Wir müssen die Genehmigung erzwingen. Vor diesen beiden Optionen muss auch die WeiterleitungURI gesetzt sein. Es hat für mich funktioniert.

Das ist meine volle Funktion

<?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;
}
17
Ulrich Dohou

Ich habe das gleiche Problem mit der neuen Google API-Bibliothek. Bei der Suche nach einer Lösung wurde der folgende Link angezeigt: RefreshToken Wird nicht zurückgeschickt, nachdem ich ein neues Token von Google Sheets API erhalten habe

Basierend auf diesen Informationen habe ich den Quickstart-Codeteil an meine Bedürfnisse angepasst. Nach der ersten Autorisierung bei Google habe ich drive-php-quickstart.json erhalten, das refresh_token enthält, das in 3600 Sekunden oder einer Stunde abläuft. Das Aktualisierungstoken wird nur einmal ausgegeben. Wenn es verloren geht, ist eine erneute Autorisierung erforderlich ..__ Damit es immer in drive-php-quickstart.json ist, habe ich Folgendes getan:

// 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)); 
}
4

Mein Rat ist: Aktualisierungs-Token in .json speichern, unmittelbar nachdem Zugriffstoken erhalten wurde und wenn das Zugriffstoken abgelaufen ist, Aktualisierungs-Token verwenden.

In meinen Projekten arbeite ich so:

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;
}
3
Michal Blažek

nur ein Update für alle, die Probleme mit dieser Nachricht haben. Meistens liegt es daran, dass nur der erste Befehl fetchAccessTokenWithAuthCode () Credencials generiert, das das Aktualisierungstoken enthält (technisch für immer gültig - keine Gültigkeit von 2 Stunden, wenn Sie es nicht widerrufen). Wenn Sie das neue erhalten, ersetzt es das ursprüngliche. Es enthält jedoch nicht das erforderliche Aktualisierungs-Token. Das nächste Mal, wenn Sie das Token aktualisieren müssen, stürzt es ab. Dies kann leicht behoben werden, indem die Aktualisierungsfunktion beispielsweise wie folgt ersetzt wird:

  // 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));
}

Jedes Mal, wenn Sie das Zugriffstoken aktualisieren, wird Ihr Aktualisierungstoken ebenfalls weitergegeben.

2
Therian

Ich hatte die gleichen Probleme und gehe schließlich zum Arbeiten:

Hintergrundgeschichte:

Ich habe den gleichen Fehler erhalten. Folgendes habe ich gefunden:

Dieser Fehler:

PHP Schwerwiegender Fehler: Nicht erfasste LogicException: Aktualisierungstoken muss in /Library/WebServer/Documents/Sites/test/scripts/vendor/google/apiclient/src/Google/Client.php als Teil von setAccessToken übergeben oder festgelegt werden : 267

Verweist auf die Update-Zugriffstoken-Methode (auch bekannt als Refresh):

$client->fetchAccessTokenWithRefreshToken($refreshTokenSaved);

Warum hat es versagt? Um es kurz zu machen, wurde mir klar, als ich das Array $ accessToken ausgedruckt hatte, das aus der Decodierung dieser Json-Datei stammt (anhand des von Ihnen geposteten Schnellstartcodes/der von Google stammt).

berechtigungsnachweise/calendar-php-quickstart.json

Ich habe den Fehler gefunden, weil das accessToken-Array bei print_r gedruckt wird:

Array ( [Access_token] => Array ( [Access_token] => xyz123 [Token_type] => Träger [Expires_in] => 3600 [Refresh_token] => xsss112222 [Erstellt] => 1511379484 )

)

Lösung:

$ refreshToken = $ accessToken ["access_token"] ["refresh_token"];

direkt vor dieser Zeile:

    $client->fetchAccessTokenWithRefreshToken($refreshToken);

Ich kann das Token nach Bedarf aktualisieren, wenn es in einer Stunde abläuft. Ich denke, die Entwickler dieses Artikels nahmen an, dass das Array folgendermaßen gedruckt wird:

Array ( [access_token] => xyz123 [token_type] => Träger [verfällt_in] => 3600 [refresh_token] => xsss112222 [erstellt] => 1511379484 )

sie dachten, Sie könnten einfach $ accessToken ["refresh_token"] machen; Das ist nicht richtig. 

Jetzt haben wir einen gültigen Wert für $ refreshToken, daher sollte der Fehler verschwinden, wenn Sie dies tun. Ich habe den Autor auch über den Feedback-Link aktualisiert, um ihn darüber zu informieren, falls andere PHP-Entwickler auf dieses Problem stoßen. Hoffentlich hilft das jemandem. Ich entschuldige mich, wenn ich diesen Beitrag schlecht formatiert habe, bin ich neu bei S.E. Ich wollte einfach nur teilen, als ich es endlich geschafft habe.

1
user3760763

Sie müssen die accestoken serialisieren, wenn Sie sie in die credentialsPath schreiben.

 // 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);

Und wenn Sie aus der Datei lesen, müssen Sie sie desialisieren.

if (file_exists($credentialsPath)) {
    $unserArray =  file_get_contents($credentialsPath);
    $accessToken = unserialize($unserArray);

}

Volle Funktion

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;
}
1

Nach einiger Zeit diesen Code anzeigen:

// 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()));
}

alles was nötig war, ist diese Änderung:

// 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()));
}

da diese Funktion $ client-> getRefreshToken () null zurückgibt, und wenn Sie das $ accessToken direkt angeben, funktioniert es einwandfrei und aktualisiert Ihre Datei.

0
oron abutbul

Google hat seinen PHP Quickstart mit einer verbesserten Methode zum Bearbeiten dieses Problems aktualisiert:

Ausschnitt unten:

// 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()));
}
0
dxdc

In meinem Fall hatte ich vergessen, den Zugriffstyp auf "offline" zu setzen, ohne dass das Aktualisierungstoken nicht generiert wurde.

$client->setAccessType('offline');

Sobald dies geschehen ist, funktioniert der in der Google-Dokumentation angegebene Beispielcode.

// 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()));
}
0
jahackbeth