2017-09-15 49 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.

相关问题