[php] Google API 클라이언트로 토큰을 새로 고치는 방법은 무엇입니까?

Google Analytics API (V3)를 가지고 놀았는데 오류가 발생했습니다. 첫째, 모든 것이 올바르게 설정되고 내 테스트 계정으로 작동합니다. 하지만 다른 프로필 ID (동일한 Google Accont / GA 계정)에서 데이터를 가져 오려면 403 오류가 발생합니다. 이상한 점은 일부 GA 계정의 데이터는 데이터를 반환하고 다른 계정은이 오류를 생성한다는 것입니다.

토큰을 취소하고 한 번 더 인증했는데 이제 모든 계정에서 데이터를 가져올 수있는 것 같습니다. 문제 해결됨? 아니. 액세스 키가 만료되면 동일한 문제가 다시 발생합니다.

내가 제대로 이해했다면 resfreshToken을 사용하여 새로운 authenticationTooken을 얻을 수 있습니다.

문제는 내가 실행할 때입니다.

$client->refreshToken(refresh_token_key)

다음 오류가 반환됩니다.

Error refreshing the OAuth2 token, message: '{ "error" : "invalid_grant" }'

나는 refreshToken 메서드 뒤에있는 코드를 확인하고 “apiOAuth2.php”파일에 대한 요청을 다시 추적했습니다. 모든 매개 변수가 올바르게 전송됩니다. grant_type은 메소드 내에서 ‘refresh_token’으로 하드 코딩되어 있으므로 무엇이 잘못되었는지 이해하기가 어렵습니다. 매개 변수 배열은 다음과 같습니다.

Array ( [client_id] => *******-uqgau8uo1l96bd09eurdub26c9ftr2io.apps.googleusercontent.com [client_secret] => ******** [refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY [grant_type] => refresh_token )

절차는 다음과 같습니다.

$client = new apiClient();
$client->setClientId($config['oauth2_client_id']);
$client->setClientSecret($config['oauth2_client_secret']);
$client->setRedirectUri($config['oauth2_redirect_uri']);
$client->setScopes('https://www.googleapis.com/auth/analytics.readonly');
$client->setState('offline');

$client->setAccessToken($config['token']); // The access JSON object.

$client->refreshToken($config['refreshToken']); // Will return error here

이것은 버그입니까, 아니면 완전히 오해 한 적이 있습니까?



답변

그래서 나는 이것을하는 방법을 마침내 알아 냈습니다. 기본 아이디어는 인증을 처음 요청할 때받는 토큰이 있다는 것입니다. 이 첫 번째 토큰에는 새로 고침 토큰이 있습니다. 첫 번째 원래 토큰은 한 시간 후에 만료됩니다. 한 시간 후에는 사용 가능한 새 토큰을 얻으려면 첫 번째 토큰의 새로 고침 토큰을 사용해야합니다. $client->refreshToken($refreshToken)새 토큰을 검색하는 데 사용 합니다. 저는 이것을 “임시 토큰”이라고 부를 것입니다. 이 임시 토큰도 저장해야합니다. 한 시간이 지나면 만료되고 연결된 새로 고침 토큰도 없기 때문입니다. 새 임시 토큰을 얻으려면 이전에 사용한 방법을 사용하고 첫 번째 토큰의 refreshtoken을 사용해야합니다. 나는 추악한 코드를 아래에 첨부했지만 이것에 새로운 메신저 …

//pull token from database
$tokenquery="SELECT * FROM token WHERE type='original'";
$tokenresult = mysqli_query($cxn,$tokenquery);
if($tokenresult!=0)
{
    $tokenrow=mysqli_fetch_array($tokenresult);
    extract($tokenrow);
}
$time_created = json_decode($token)->created;
$t=time();
$timediff=$t-$time_created;
echo $timediff."<br>";
$refreshToken= json_decode($token)->refresh_token;


//start google client note:
$client = new Google_Client();
$client->setApplicationName('');
$client->setScopes(array());
$client->setClientId('');
$client->setClientSecret('');
$client->setRedirectUri('');
$client->setAccessType('offline');
$client->setDeveloperKey('');

//resets token if expired
if(($timediff>3600)&&($token!=''))
{
    echo $refreshToken."</br>";
    $refreshquery="SELECT * FROM token WHERE type='refresh'";
    $refreshresult = mysqli_query($cxn,$refreshquery);
    //if a refresh token is in there...
    if($refreshresult!=0)
    {
        $refreshrow=mysqli_fetch_array($refreshresult);
        extract($refreshrow);
        $refresh_created = json_decode($token)->created;
        $refreshtimediff=$t-$refresh_created;
        echo "Refresh Time Diff: ".$refreshtimediff."</br>";
        //if refresh token is expired
        if($refreshtimediff>3600)
        {
            $client->refreshToken($refreshToken);
        $newtoken=$client->getAccessToken();
        echo $newtoken."</br>";
        $tokenupdate="UPDATE token SET token='$newtoken' WHERE type='refresh'";
        mysqli_query($cxn,$tokenupdate);
        $token=$newtoken;
        echo "refreshed again";
        }
        //if the refresh token hasn't expired, set token as the refresh token
        else
        {
        $client->setAccessToken($token);
           echo "use refreshed token but not time yet";
        }
    }
    //if a refresh token isn't in there...
    else
    {
        $client->refreshToken($refreshToken);
        $newtoken=$client->getAccessToken();
        echo $newtoken."</br>";
        $tokenupdate="INSERT INTO token (type,token) VALUES ('refresh','$newtoken')";
        mysqli_query($cxn,$tokenupdate);
        $token=$newtoken;
        echo "refreshed for first time";
    }
}

//if token is still good.
if(($timediff<3600)&&($token!=''))
{
    $client->setAccessToken($token);
}

$service = new Google_DfareportingService($client);


답변

문제는 새로 고침 토큰에 있습니다.

[refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

가있는 문자열이 '/'get json encoded이면 a 로 이스케이프 '\'되므로 제거해야합니다.

사례의 새로 고침 토큰은 다음과 같아야합니다.

1/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

무엇 난 당신이 한 겠지하면 경우에 때문에 당신이 구글에서 다시 전송 된 JSON 문자열을 인쇄하고 복사 코드에 토큰 붙여 넣은 것입니다 json_decode그 다음이 제대로 제거됩니다 '\'당신을 위해!


답변

다음은 토큰을 설정하는 스 니펫입니다. 그 전에 액세스 유형을 오프라인 으로 설정해야합니다.

if (isset($_GET['code'])) {
  $client->authenticate();
  $_SESSION['access_token'] = $client->getAccessToken();
}

토큰을 새로 고치려면

$google_token= json_decode($_SESSION['access_token']);
$client->refreshToken($google_token->refresh_token);

이것은 당신의 토큰을 새로 고칠 것입니다, 당신은 당신이 할 수있는 세션에서 그것을 업데이트해야합니다

 $_SESSION['access_token']= $client->getAccessToken()


답변

액세스 유형은로 설정해야합니다 offline. stateAPI의 사용이 아닌 사용자가 직접 사용하도록 설정 한 변수입니다.

최신 버전의 클라이언트 라이브러리 가 있는지 확인 하고 다음을 추가합니다.

$client->setAccessType('offline');

매개 변수에 대한 설명은 URL 형성을 참조하십시오 .


답변

@ uri-weg가 올린 답변은 저에게 효과적 이었지만 그의 설명이 명확하지 않았으므로 조금 다시 말하겠습니다.

첫 번째 액세스 권한 시퀀스 동안 콜백에서 인증 코드를받은 지점에 도달 하면 액세스 토큰과 새로 고침 토큰저장 해야합니다 .

그 이유는 google api가 액세스 권한을 요청하는 경우에만 새로 고침 토큰이 포함 된 액세스 토큰을 전송하기 때문입니다. 다음 액세스 토큰은 새로 고침 토큰없이 전송됩니다 ( approval_prompt=force옵션 을 사용하지 않는 경우 ).

처음받은 새로 고침 토큰은 사용자가 액세스 권한을 취소 할 때까지 유효합니다.

단순한 PHP에서 콜백 시퀀스의 예는 다음과 같습니다.

// init client
// ...

$authCode = $_GET['code'];
$accessToken = $client->authenticate($authCode);
// $accessToken needs to be serialized as json
$this->saveAccessToken(json_encode($accessToken));
$this->saveRefreshToken($accessToken['refresh_token']);

그리고 나중에 단순한 PHP에서 연결 순서는 다음과 같습니다.

// init client
// ...

$accessToken = $this->loadAccessToken();
// setAccessToken() expects json
$client->setAccessToken($accessToken);

if ($client->isAccessTokenExpired()) {
    // reuse the same refresh token
    $client->refreshToken($this->loadRefreshToken());
    // save the new access token (which comes without any refresh token)
    $this->saveAccessToken($client->getAccessToken());
}


답변

내 프로젝트에서 사용중인 코드는 다음과 같습니다.

public function getClient(){
    $client = new Google_Client();
    $client->setApplicationName(APPNAME);       // app name
    $client->setClientId(CLIENTID);             // client id
    $client->setClientSecret(CLIENTSECRET);     // client secret 
    $client->setRedirectUri(REDIRECT_URI);      // redirect uri
    $client->setApprovalPrompt('auto');

    $client->setAccessType('offline');         // generates refresh token

    $token = $_COOKIE['ACCESSTOKEN'];          // fetch from cookie

    // if token is present in cookie
    if($token){
        // use the same token
        $client->setAccessToken($token);
    }

    // this line gets the new token if the cookie token was not present
    // otherwise, the same cookie token
    $token = $client->getAccessToken();

    if($client->isAccessTokenExpired()){  // if token expired
        $refreshToken = json_decode($token)->refresh_token;

        // refresh the token
        $client->refreshToken($refreshToken);
    }

    return $client;
}


답변

같은 문제가있었습니다. 어제 작동했던 내 대본은 이상한 이유로 오늘은 그렇지 않았습니다. 변화가 없다.

분명히 이것은 내 시스템 시계가 2.5 (!!) 초 떨어져서 NTP와 동기화되어 문제가 해결 되었기 때문입니다.

참조 : https://code.google.com/p/google-api-php-client/wiki/OAuth2#Solving_invalid_grant_errors