Saya telah bermain-main dengan Google Analytics API (V3) dan mengalami beberapa kesalahan. Pertama, semuanya sudah diatur dengan benar dan berfungsi dengan akun pengujian saya. Tetapi ketika saya ingin mengambil data dari ID profil lain (Akun Google Accont / GA yang Sama) saya mendapatkan Kesalahan 403. Yang aneh adalah bahwa data dari beberapa akun GA akan mengembalikan data sementara yang lain menghasilkan kesalahan ini.
Saya telah mencabut token dan mengautentikasi sekali lagi, dan sekarang sepertinya saya dapat mengambil data dari semua akun saya. Masalah terpecahkan? Tidak. Karena kunci akses akan kedaluwarsa, saya akan mengalami masalah yang sama lagi.
Jika saya telah memahami semuanya dengan benar, seseorang dapat menggunakan resfreshToken untuk mendapatkan authenticationTooken baru.
Masalahnya adalah, saat saya menjalankan:
$client->refreshToken(refresh_token_key)
kesalahan berikut dikembalikan:
Error refreshing the OAuth2 token, message: '{ "error" : "invalid_grant" }'
Saya telah memeriksa kode di belakang metode refreshToken dan melacak permintaan kembali ke file "apiOAuth2.php". Semua parameter dikirim dengan benar. Grant_type dikodekan keras menjadi 'refresh_token' dalam metode, jadi sulit bagi saya untuk memahami apa yang salah. Array parameter terlihat seperti ini:
Array ( [client_id] => *******-uqgau8uo1l96bd09eurdub26c9ftr2io.apps.googleusercontent.com [client_secret] => ******** [refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY [grant_type] => refresh_token )
Prosedurnya adalah sebagai berikut.
$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
Apakah ini bug, atau apakah saya benar-benar salah paham?
sumber
Jawaban:
Jadi saya akhirnya menemukan cara untuk melakukan ini. Ide dasarnya adalah Anda memiliki token yang Anda dapatkan saat pertama kali meminta otentikasi. Token pertama ini memiliki token penyegaran. Token asli pertama kedaluwarsa setelah satu jam. Setelah satu jam, Anda harus menggunakan token penyegaran dari token pertama untuk mendapatkan token baru yang dapat digunakan. Anda gunakan
$client->refreshToken($refreshToken)
untuk mengambil token baru. Saya akan menyebutnya "temp token". Anda perlu menyimpan token temp ini juga karena setelah satu jam, token tersebut juga akan kedaluwarsa dan perhatikan bahwa token penyegaran tidak terkait dengannya. Untuk mendapatkan token temp baru, Anda perlu menggunakan metode yang Anda gunakan sebelumnya dan menggunakan refreshtoken token pertama. Saya telah melampirkan kode di bawah ini, yang jelek, tetapi saya baru dalam hal ini ...//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);
sumber
$client->isAccessTokenExpired()
masih hanya akan memeriksa waktu yang ditahan secara lokal untuk melihat apakah menurutnya token telah kedaluwarsa. Token mungkin masih kedaluwarsa dan aplikasi lokal hanya akan benar-benar tahu ketika mencoba menggunakannya. Dalam kasus ini, klien API akan mengembalikan pengecualian, dan tidak akan secara otomatis menyegarkan token.Masalahnya ada pada token penyegaran:
[refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY
Ketika sebuah string dengan
'/'
getjson encoded
, itu lolos dengan a'\'
, maka Anda perlu menghapusnya.Token penyegaran dalam kasus Anda harus:
1/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY
Apa yang saya anggap telah Anda lakukan adalah Anda telah mencetak string json yang dikirim kembali oleh google dan menyalin dan menempelkan token ke dalam kode Anda karena jika Anda
json_decode
melakukannya maka itu akan menghapus dengan benar'\'
untuk Anda!sumber
berikut adalah cuplikan untuk menyetel token, sebelum itu pastikan jenis akses harus disetel ke offline
if (isset($_GET['code'])) { $client->authenticate(); $_SESSION['access_token'] = $client->getAccessToken(); }
Untuk menyegarkan token
$google_token= json_decode($_SESSION['access_token']); $client->refreshToken($google_token->refresh_token);
ini akan menyegarkan token Anda, Anda harus memperbaruinya dalam sesi untuk yang dapat Anda lakukan
$_SESSION['access_token']= $client->getAccessToken()
sumber
Jenis akses harus disetel ke
offline
.state
adalah variabel yang Anda setel untuk Anda gunakan sendiri, bukan untuk penggunaan API.Pastikan Anda memiliki versi terbaru pustaka klien dan tambahkan:
$client->setAccessType('offline');
Lihat Membentuk URL untuk penjelasan tentang parameter.
sumber
$client
($client = new apiClient();
) untuk menggunakan token penyegaran?$client->setApprovalPrompt('force')
serta$client->setAccessType('offline')
mendapatkan token penyegaran baru selama otorisasi. Tanpa memaksa pengguna untuk menyetujui cakupan akses, Google berasumsi Anda akan tetap menggunakan token penyegaran yang lama.Jawaban yang diposting oleh @ uri-weg berhasil untuk saya, tetapi karena saya tidak menemukan penjelasannya yang sangat jelas, izinkan saya mengubah sedikit.
Selama urutan izin akses pertama, dalam panggilan balik, saat Anda mencapai titik di mana Anda menerima kode otentikasi, Anda harus menyimpan token akses dan token penyegaran. juga.
Alasannya adalah google api mengirimi Anda token akses dengan token penyegaran hanya ketika meminta izin akses. Token akses berikutnya akan dikirim tanpa token penyegaran apa pun (kecuali Anda menggunakan
approval_prompt=force
opsi tersebut).Token penyegaran yang Anda terima pertama kali tetap valid sampai pengguna mencabut izin akses.
Dalam php sederhana, contoh urutan panggilan balik adalah:
// 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']);
Dan selanjutnya, dalam php yang sederhana, urutan koneksi adalah:
// 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()); }
sumber
// setAccessToken() expects json
sudah cukup. Atau untuk bagian lain dari kode?Berikut adalah kode yang saya gunakan dalam proyek saya dan berfungsi dengan baik:
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; }
sumber
Memiliki masalah yang sama; skrip saya yang bekerja kemarin, untuk beberapa alasan aneh tidak hari ini. Tidak ada perubahan.
Rupanya ini karena jam sistem saya mati selama 2,5 (!!) detik, disinkronkan dengan NTP memperbaikinya.
Lihat juga: https://code.google.com/p/google-api-php-client/wiki/OAuth2#Solving_invalid_grant_errors
sumber
sudo apt-get install ntp
di mesin Debian saya untuk menginstal NTP. Ini menyinkronkan jam dan masalahnya terpecahkan.FYI: API Google Analytics 3.0 akan secara otomatis menyegarkan token akses jika Anda memiliki token penyegaran ketika kadaluwarsa sehingga skrip Anda tidak perlu
refreshToken
.(Lihat
Sign
fungsinya diauth/apiOAuth2.php
)sumber
Terkadang Refresh Token yang tidak saya buat dengan menggunakan
$client->setAccessType ("offline");
.Coba ini:
$client->setAccessType ("offline"); $client->setApprovalPrompt ("force");
sumber
Saya menggunakan contoh dengan smartcode dengan versi Google API saat ini, tetapi yang itu tidak berfungsi. Saya pikir API-nya terlalu ketinggalan jaman.
Jadi, saya baru saja menulis versi saya sendiri, berdasarkan salah satu contoh API ... Ini mengeluarkan token akses, token permintaan, jenis token, token ID, waktu kedaluwarsa, dan waktu pembuatan sebagai string
Jika kredensial klien dan kunci pengembang Anda benar, kode ini seharusnya berfungsi di luar kotak.
<?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>
sumber
$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
. Mengapa Anda mengalihkan ke halaman yang sama? apakah ini perlu?Anda perlu menyimpan token akses ke file atau database sebagai string json selama permintaan otorisasi awal, dan menyetel jenis akses ke offline
$client->setAccessType("offline")
Kemudian, selama permintaan api berikutnya, ambil token akses dari file atau db Anda dan teruskan ke klien:
$accessToken = json_decode($row['token'], true); $client->setAccessToken($accessToken);
Sekarang Anda perlu memeriksa apakah token telah kedaluwarsa:
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())
The
fetchAccessTokenWithRefreshToken()
fungsi akan melakukan pekerjaan untuk Anda dan memberikan tanda akses baru, simpan kembali ke file Anda atau database.sumber
Saya memiliki masalah yang sama dengan google / google-api-php-client v2.0.0-RC7 dan setelah mencari selama 1 jam, saya menyelesaikan masalah ini menggunakan json_encode seperti ini:
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())); }
sumber
Ini bekerja dengan sangat baik, mungkin bisa membantu siapa saja:
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(); } ?>
sumber
Google telah membuat beberapa perubahan sejak pertanyaan ini pertama kali diposting.
Berikut adalah contoh pekerjaan saya saat ini.
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); } } }
sumber
Saya menggunakan google-api-php-client v2.2.2 Saya mendapatkan token baru dengan
fetchAccessTokenWithRefreshToken();
panggilan fungsi if tanpa params, ia mengembalikan token akses yang diperbarui dan token yang diperbarui tidak hilang.if ($client->getAccessToken() && $client->isAccessTokenExpired()) { $new_token=$client->fetchAccessTokenWithRefreshToken(); $token_data = $client->verifyIdToken(); }
sumber
gunakan cuplikan kode berikut untuk mendapatkan token penyegaran Anda
<?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']; ?>
sumber
Menurut Otentikasi di google: OAuth2 terus mengembalikan 'invalid_grant'
"Anda harus menggunakan kembali token akses yang Anda peroleh setelah otentikasi pertama yang berhasil. Anda akan mendapatkan kesalahan invalid_grant jika token Anda sebelumnya belum kedaluwarsa. Simpan dalam cache di suatu tempat sehingga Anda dapat menggunakannya kembali."
semoga membantu
sumber