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
. state
API의 사용이 아닌 사용자가 직접 사용하도록 설정 한 변수입니다.
최신 버전의 클라이언트 라이브러리 가 있는지 확인 하고 다음을 추가합니다.
$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
참고 : 3.0 Google Analytics API는 만료 될 때 새로 고침 토큰이있는 경우 액세스 토큰을 자동으로 새로 고침하므로 스크립트에 refreshToken
.
(의 Sign
기능 참조 auth/apiOAuth2.php
)
때때로 새로 고침 토큰을 사용하여 생성하지 않았습니다 $client->setAccessType ("offline");
.
이 시도:
$client->setAccessType ("offline");
$client->setApprovalPrompt ("force");
현재 버전의 Google API에서 스마트 코드로 예제를 사용했지만 작동하지 않았습니다. 그의 API가 너무 구식이라고 생각합니다.
그래서 API 예제 중 하나를 기반으로 자체 버전을 작성했습니다. 액세스 토큰, 요청 토큰, 토큰 유형, ID 토큰, 만료 시간 및 생성 시간을 문자열로 출력합니다.
클라이언트 자격 증명과 개발자 키가 올 바르면이 코드가 즉시 작동합니다.
<?php
// Call set_include_path() as needed to point to your client library.
require_once 'google-api-php-client/src/Google_Client.php';
require_once 'google-api-php-client/src/contrib/Google_Oauth2Service.php';
session_start();
$client = new Google_Client();
$client->setApplicationName("Get Token");
// Visit https://code.google.com/apis/console?api=plus to generate your
// oauth2_client_id, oauth2_client_secret, and to register your oauth2_redirect_uri.
$oauth2 = new Google_Oauth2Service($client);
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$_SESSION['token'] = $client->getAccessToken();
$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
return;
}
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
}
if (isset($_REQUEST['logout'])) {
unset($_SESSION['token']);
$client->revokeToken();
}
?>
<!doctype html>
<html>
<head><meta charset="utf-8"></head>
<body>
<header><h1>Get Token</h1></header>
<?php
if ($client->getAccessToken()) {
$_SESSION['token'] = $client->getAccessToken();
$token = json_decode($_SESSION['token']);
echo "Access Token = " . $token->access_token . '<br/>';
echo "Refresh Token = " . $token->refresh_token . '<br/>';
echo "Token type = " . $token->token_type . '<br/>';
echo "Expires in = " . $token->expires_in . '<br/>';
echo "ID Token = " . $token->id_token . '<br/>';
echo "Created = " . $token->created . '<br/>';
echo "<a class='logout' href='?logout'>Logout</a>";
} else {
$authUrl = $client->createAuthUrl();
print "<a class='login' href='$authUrl'>Connect Me!</a>";
}
?>
</body>
</html>
google / google-api-php-client v2.0.0-RC7 과 동일한 문제가 있으며 1 시간 동안 검색 한 후 다음 과 같이 json_encode를 사용하여이 문제를 해결 했습니다.
if ($client->isAccessTokenExpired()) {
$newToken = json_decode(json_encode($client->getAccessToken()));
$client->refreshToken($newToken->refresh_token);
file_put_contents(storage_path('app/client_id.txt'), json_encode($client->getAccessToken()));
}
이것은 여기에서 매우 잘 작동합니다. 아마도 누구에게나 도움이 될 수 있습니다.
index.php
session_start();
require_once __DIR__.'/client.php';
if(!isset($obj->error) && isset($_SESSION['access_token']) && $_SESSION['access_token'] && isset($obj->expires_in)) {
?>
<!DOCTYPE html>
<html>
<head>
<title>Google API Token Test</title>
<meta charset='utf-8' />
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script>
search('Music Mix 2010');
function search(q) {
$.ajax({
type: 'GET',
url: 'action.php?q='+q,
success: function(data) {
if(data == 'refresh') location.reload();
else $('#response').html(JSON.stringify(JSON.parse(data)));
}
});
}
</script>
</head>
<body>
<div id="response"></div>
</body>
</html>
<?php
}
else header('Location: '.filter_var('https://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']).'/oauth2callback.php', FILTER_SANITIZE_URL));
?>
oauth2callback.php
require_once __DIR__.'/vendor/autoload.php';
session_start();
$client = new Google_Client();
$client->setAuthConfigFile('auth.json');
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$client->setRedirectUri('https://'.filter_var($_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'], FILTER_SANITIZE_URL));
$client->addScope(Google_Service_YouTube::YOUTUBE_FORCE_SSL);
if(isset($_GET['code']) && $_GET['code']) {
$client->authenticate(filter_var($_GET['code'], FILTER_SANITIZE_STRING));
$_SESSION['access_token'] = $client->getAccessToken();
$_SESSION['refresh_token'] = $_SESSION['access_token']['refresh_token'];
setcookie('refresh_token', $_SESSION['refresh_token'], time()+60*60*24*180, '/', filter_var($_SERVER['HTTP_HOST'], FILTER_SANITIZE_URL), true, true);
header('Location: '.filter_var('https://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']), FILTER_SANITIZE_URL));
exit();
}
else header('Location: '.filter_var($client->createAuthUrl(), FILTER_SANITIZE_URL));
exit();
?>
client.php
// https://developers.google.com/api-client-library/php/start/installation
require_once __DIR__.'/vendor/autoload.php';
$client = new Google_Client();
$client->setAuthConfig('auth.json');
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$client->addScope(Google_Service_YouTube::YOUTUBE_FORCE_SSL);
// Delete Cookie Token
#setcookie('refresh_token', @$_SESSION['refresh_token'], time()-1, '/', filter_var($_SERVER['HTTP_HOST'], FILTER_SANITIZE_URL), true, true);
// Delete Session Token
#unset($_SESSION['refresh_token']);
if(isset($_SESSION['refresh_token']) && $_SESSION['refresh_token']) {
$client->refreshToken($_SESSION['refresh_token']);
$_SESSION['access_token'] = $client->getAccessToken();
}
elseif(isset($_COOKIE['refresh_token']) && $_COOKIE['refresh_token']) {
$client->refreshToken($_COOKIE['refresh_token']);
$_SESSION['access_token'] = $client->getAccessToken();
}
$url = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token='.urlencode(@$_SESSION['access_token']['access_token']);
$curl_handle = curl_init();
curl_setopt($curl_handle, CURLOPT_URL, $url);
curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_handle, CURLOPT_USERAGENT, 'Google API Token Test');
$json = curl_exec($curl_handle);
curl_close($curl_handle);
$obj = json_decode($json);
?>
action.php
session_start();
require_once __DIR__.'/client.php';
if(isset($obj->error)) {
echo 'refresh';
exit();
}
elseif(isset($_SESSION['access_token']) && $_SESSION['access_token'] && isset($obj->expires_in) && isset($_GET['q']) && !empty($_GET['q'])) {
$client->setAccessToken($_SESSION['access_token']);
$service = new Google_Service_YouTube($client);
$response = $service->search->listSearch('snippet', array('q' => filter_input(INPUT_GET, 'q', FILTER_SANITIZE_SPECIAL_CHARS), 'maxResults' => '1', 'type' => 'video'));
echo json_encode($response['modelData']);
exit();
}
?>
google-api-php-client v2.2.2를 사용 fetchAccessTokenWithRefreshToken();
합니다. 매개 변수없이 if 함수 호출을 사용하여 새 토큰을 얻 습니다. 업데이트 된 액세스 토큰이 반환되고 새로 고침 된 토큰이 손실되지 않습니다.
if ($client->getAccessToken() && $client->isAccessTokenExpired()) {
$new_token=$client->fetchAccessTokenWithRefreshToken();
$token_data = $client->verifyIdToken();
}
Google의 인증에 따르면 OAuth2가 계속 'invalid_grant'를 반환합니다.
"첫 번째 인증 성공 후에 얻은 액세스 토큰을 재사용해야합니다. 이전 토큰이 아직 만료되지 않은 경우 invalid_grant 오류가 발생합니다. 재사용 할 수 있도록 어딘가에 캐시합니다."
도움이 되길 바랍니다
이 질문이 처음 게시 된 이후 Google은 몇 가지 사항을 변경했습니다.
다음은 현재 작업중인 예입니다.
public function update_token($token){
try {
$client = new Google_Client();
$client->setAccessType("offline");
$client->setAuthConfig(APPPATH . 'vendor' . DIRECTORY_SEPARATOR . 'google' . DIRECTORY_SEPARATOR . 'client_secrets.json');
$client->setIncludeGrantedScopes(true);
$client->addScope(Google_Service_Calendar::CALENDAR);
$client->setAccessToken($token);
if ($client->isAccessTokenExpired()) {
$refresh_token = $client->getRefreshToken();
if(!empty($refresh_token)){
$client->fetchAccessTokenWithRefreshToken($refresh_token);
$token = $client->getAccessToken();
$token['refresh_token'] = json_decode($refresh_token);
$token = json_encode($token);
}
}
return $token;
} catch (Exception $e) {
$error = json_decode($e->getMessage());
if(isset($error->error->message)){
log_message('error', $error->error->message);
}
}
}
초기 인증 요청시 액세스 토큰을 파일 또는 데이터베이스에 json 문자열로 저장하고 액세스 유형을 오프라인으로 설정해야합니다. $client->setAccessType("offline")
그런 다음 후속 API 요청 중에 파일 또는 db에서 액세스 토큰을 가져와 클라이언트에 전달합니다.
$accessToken = json_decode($row['token'], true);
$client->setAccessToken($accessToken);
이제 토큰이 만료되었는지 확인해야합니다.
if ($client->isAccessTokenExpired()) {
// access token has expired, use the refresh token to obtain a new one
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
// save the new token to file or db
// ...json_encode($client->getAccessToken())
이 fetchAccessTokenWithRefreshToken()
함수는 사용자를 위해 작업을 수행하고 새 액세스 토큰을 제공하고 파일 또는 데이터베이스에 다시 저장합니다.
다음 코드 조각을 사용하여 새로 고침 토큰을 가져옵니다.
<?php
require_once 'src/apiClient.php';
require_once 'src/contrib/apiTasksService.php';
$client = new apiClient();
$client->setAccessType('offline');
$tasksService = new apiTasksService($client);
$auth = $client->authenticate();
$token = $client->getAccessToken();
// the refresh token
$refresh_token = $token['refresh_token'];
?>
참고 URL : https://stackoverflow.com/questions/9241213/how-to-refresh-token-with-google-api-client
'Programing' 카테고리의 다른 글
Eclipse Git 플러그인에서 기본 작성자 및 커미터를 어떻게 변경합니까? (0) | 2020.09.13 |
---|---|
Amazon API Gateway에서 반환 한 http 상태 코드를 변경하는 방법이 있습니까? (0) | 2020.09.13 |
GitHub : "wip"브랜치 란 무엇입니까? (0) | 2020.09.13 |
단일 SQL에 여러 "WITH AS"를 사용할 수 있습니까?-Oracle SQL (0) | 2020.09.13 |
Python을 사용하여 네이티브 iPhone 앱을 작성할 수 있습니까? (0) | 2020.09.13 |