2017-09-15 148 views
0

使用PHP Quickstart代碼時,我發現一個問題:當需要刷新令牌時,代碼返回以下錯誤:Google API致命錯誤:未捕獲LogicException:必須將刷新令牌傳入或設置爲setAccessToken的一部分

Fatal error: Uncaught LogicException: refresh token must be passed in or set as part of setAccessToken in /app/vendor/google/apiclient/src/Google/Client.php:258

Stack trace:

#0 /app/gmail.php(32): Google_Client->fetchAccessTokenWithRefreshToken(NULL)

#1 /app/test.php(14): getClient()

#2 {main} thrown in /app/vendor/google/apiclient/src/Google/Client.php on line 258

我修改getClient()函數是這樣的:

function getClient() { 
    $client = new Google_Client(); 
    $client->setApplicationName(APPLICATION_NAME); 
    $client->setScopes(SCOPES); 
    $client->setAuthConfig(CLIENT_SECRET_PATH); 
    $client->setRedirectUri(REDIRECT_URL); 
    $client->setAccessType('offline'); 
    $client->setApprovalPrompt('force'); 

    // Load previously authorized credentials from a file. 
    $credentialsPath = expandHomeDirectory(CREDENTIALS_PATH); 

    if (file_exists($credentialsPath)) { 
     $accessToken = json_decode(file_get_contents($credentialsPath), true); 
    } 
    else { 
     // Request authorization from the user. 
     $authUrl = $client->createAuthUrl(); 
     return printf("<a href='%s' target='_blank'>auth</a><br />", $authUrl); 
    } 
    $client->setAccessToken($accessToken); 

    // Refresh the token if it's expired. 
    // ERROR HERE !! 
    if ($client->isAccessTokenExpired()) { 
     $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken()); 
     file_put_contents($credentialsPath, json_encode($client->getAccessToken())); 
    } 
    return $client; 
} 

第一認證後(使用在getClient()函數創建的鏈接),當用戶的土地上REDIRECT_URL一個,執行功能:

function callbackAuth() { 
    $client = new Google_Client(); 
    $client->setApplicationName(APPLICATION_NAME); 
    $client->setScopes(SCOPES); 
    $client->setAuthConfig(CLIENT_SECRET_PATH); 
    $client->setRedirectUri(REDIRECT_URL); 
    $client->setAccessType('offline'); 
    $client->setApprovalPrompt('force'); 

    // Load previously authorized credentials from a file. 
    $credentialsPath = expandHomeDirectory(CREDENTIALS_PATH); 

    // Request authorization from the user. 
    $authCode = trim($_GET['code']); 

    // Exchange authorization code for an access token. 
    $accessToken = $client->fetchAccessTokenWithAuthCode($authCode); 

    // Store the credentials to disk. 
    if(!file_exists(dirname($credentialsPath))) { 
     mkdir(dirname($credentialsPath), 0700, true); 
    } 
    file_put_contents($credentialsPath, json_encode($accessToken)); 
    printf("Credentials saved to %s\n", $credentialsPath); 

    $client->setAccessToken($accessToken); 

    return $client; 
} 

我嘗試申請其他相關stackoverflow question的解決方案,但沒有結果。爲什麼這個錯誤會導致?

+1

你確認你的令牌有刷新令牌,密鑰是'refresh_token'?錯誤表明它沒有。 –

+0

我檢查了令牌,它只包含'access_token','token_type','expires_in'和'created'屬性。我如何檢索'refresh_token'屬性? – cespon

+0

錯誤沒有說。請參閱文檔。你如何獲得access_token? –

回答

0

感謝Alex Blex我能夠注意到,我第一次收到令牌時有refresh_token,但在第一次請求後,refresh_token未被存儲。解決的辦法是以下(from this answer):「加載以前授權證書從文件」

// Refresh the token if it's expired. 
if ($client->isAccessTokenExpired()) { 
    $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken()); 
    $newAccessToken = $client->getAccessToken(); 
    $accessToken = array_merge($accessToken, $newAccessToken); 
    file_put_contents($credentialsPath, json_encode($accessToken)); 
} 

The refresh_token is only returned on the first request. When you refresh the access token a second time it returns everything except the refresh_token and the file_put_contents removes the refresh_token when this happens the second time.

Modifying the code as following will merge in the original access token with the new one. This way you will be able to preserve your refresh_token for future requests.

相關問題