จะรีเฟรชโทเค็นด้วยไคลเอนต์ Google API ได้อย่างไร


92

ฉันได้เล่นกับ Google Analytics API (V3) และพบข้อผิดพลาดบางอย่าง ประการแรกทุกอย่างตั้งค่าถูกต้องและทำงานร่วมกับบัญชีทดสอบของฉัน แต่เมื่อฉันต้องการดึงข้อมูลจากรหัสโปรไฟล์อื่น (บัญชี Google Accont / GA เดียวกัน) ฉันได้รับข้อผิดพลาด 403 สิ่งที่แปลกคือข้อมูลจากบัญชี GA บางบัญชีจะส่งคืนข้อมูลในขณะที่อีกบัญชีสร้างข้อผิดพลาดนี้

ฉันได้เพิกถอนโทเค็นและตรวจสอบสิทธิ์อีกครั้งและตอนนี้ดูเหมือนว่าฉันสามารถดึงข้อมูลจากบัญชีทั้งหมดของฉันได้ แก้ไขปัญหา? ไม่. เนื่องจากคีย์การเข้าถึงจะหมดอายุฉันจะพบปัญหาเดิมอีกครั้ง

หากฉันเข้าใจสิ่งต่างๆถูกต้องเราสามารถใช้ resfreshToken เพื่อรับการรับรองความถูกต้องใหม่ได้

ปัญหาคือเมื่อฉันเรียกใช้:

$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

นี่เป็นข้อบกพร่องหรือว่าฉันเข้าใจผิดไปหมด?


ไม่รู้ว่าเป็นบั๊กหรืออะไร แต่ฉันกำลังรีเฟรชโทเค็นการเข้าถึงโดยใช้คำขอ CURL http แบบดิบและใช้งานได้ดี
gremo

Seorch ... คุณคิดออกหรือยัง? ปัญหาเดียวกันที่นี่
Brian Vanderbusch

@gremo คุณสามารถแบ่งปันคำขอ CURL http ดิบที่คุณใช้ที่นี่ได้หรือไม่ จะเป็นประโยชน์จริงๆ ขอบคุณ!
Silver Ringvee

คำตอบ:


76

ในที่สุดฉันก็คิดหาวิธีทำ แนวคิดพื้นฐานคือคุณมีโทเค็นที่คุณได้รับในครั้งแรกที่ขอการตรวจสอบสิทธิ์ โทเค็นแรกนี้มีโทเค็นการรีเฟรช โทเค็นดั้งเดิมแรกจะหมดอายุภายในหนึ่งชั่วโมง หลังจากผ่านไปหนึ่งชั่วโมงคุณต้องใช้โทเค็นการรีเฟรชจากโทเค็นแรกเพื่อรับโทเค็นที่ใช้งานได้ใหม่ คุณใช้$client->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);

52
แทนที่จะตรวจสอบเป็นเวลา 3600 วินาทีคุณควรใช้ $ client-> isAccessTokenExpired ()
Gaurav Gupta

2
อัปเดตขนาดเล็ก ในเวอร์ชันล่าสุดเมื่อคุณร้องขอโทเค็นการรีเฟรชโทเค็นการเข้าถึงใหม่ที่ส่งคืนจะมาพร้อมกับโทเค็นการรีเฟรชใหม่ โดยพื้นฐานแล้วคุณสามารถใช้โทเค็น json ที่อัปเดตเพื่อแทนที่โทเค็น json ก่อนหน้านี้และไม่จำเป็นต้องเก็บโทเค็นการเข้าถึงเริ่มต้นอีกต่อไป .
skidadon

1
โปรดทราบว่า$client->isAccessTokenExpired()จะยังตรวจสอบเฉพาะเวลาที่จัดขึ้นในเครื่องเพื่อดูว่าโทเค็นหมดอายุหรือไม่ โทเค็นอาจยังหมดอายุอยู่และแอปพลิเคชันในระบบจะรู้จริงก็ต่อเมื่อพยายามใช้งานเท่านั้น ในกรณีนี้ไคลเอ็นต์ API จะส่งคืนข้อยกเว้นและจะไม่รีเฟรชโทเค็นโดยอัตโนมัติ
Jason

@ Jason ไม่จริงตอนนี้ฉันคิดว่า ฉันเห็นคำสั่ง return ด้านล่างในเมธอด "isAccessTokenExpired": return ($ created + ($ this-> token ['expires_in'] - 30)) <time ();
sudip

44

ปัญหาอยู่ในโทเค็นการรีเฟรช:

[refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

เมื่อสตริงที่มีการ'/'รับjson encodedมันจะหนีด้วย a '\'ดังนั้นคุณต้องลบออก

โทเค็นการรีเฟรชในกรณีของคุณควรเป็น:

1/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

สิ่งที่ฉันสมมติว่าคุณทำคือคุณได้พิมพ์สตริง json ซึ่ง google ส่งกลับมาและคัดลอกและวางโทเค็นลงในรหัสของคุณเพราะถ้าคุณjson_decodeเป็นเช่นนั้นมันจะลบออก'\'ให้คุณอย่างถูกต้อง!


1
การกล่าวถึงที่น่าอัศจรรย์ทำให้วันของฉัน! ประหยัดได้หลายชั่วโมง!
Mircea Sandu

คุณช่วยวันของฉัน!
Truong Dang

ฉันหวังว่าฉันจะโหวตให้คะแนน 100 ครั้งนี้ ฉันกำลังจะเจาะผนังด้วยแป้นพิมพ์หลังจากจ้องมองข้อความ "การให้สิทธิ์ที่ไม่เหมาะสม" เป็นเวลาหลายชั่วโมงหลังจากพยายามทำทุกอย่างเพื่อให้โทเค็นใช้งานได้จริง ทำไมต้องใช้เครื่องหมายทับทำไม?
Askerman

18

นี่คือตัวอย่างข้อมูลสำหรับตั้งค่าโทเค็นก่อนหน้านั้นตรวจสอบให้แน่ใจว่าประเภทการเข้าถึงควรตั้งค่าเป็นออฟไลน์

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()

1
คุณทำให้วันของฉันมีสิ่งนี้ :) ขอบคุณมากง่ายกว่าที่ฉันคิดไว้มากเพราะฉันใช้เวลามากมายในการไปไหนมาไหน: D
TB Ygg

16

offlineประเภทการเข้าถึงควรจะกำหนดให้ stateเป็นตัวแปรที่คุณตั้งค่าสำหรับการใช้งานของคุณเองไม่ใช่การใช้งานของ API

ตรวจสอบให้แน่ใจว่าคุณมีไลบรารีไคลเอ็นต์เวอร์ชันล่าสุดและเพิ่ม:

$client->setAccessType('offline');

ดูการสร้าง URLสำหรับคำอธิบายเกี่ยวกับพารามิเตอร์


ขอบคุณ jk. ฉันดาวน์โหลดเวอร์ชันล่าสุดและเพิกถอนการเข้าถึงแอปสำหรับบัญชีของฉัน จากนั้นฉันให้สิทธิ์เข้าถึงอีกครั้งและจัดเก็บ accessToken และ refreshToken สิ่งนี้คือฉันได้รับ refreshToken มาตลอดแม้ว่า setAccessType จะถูกละไว้ อย่างไรก็ตามเมื่อฉันเรียกใช้ $ client-> refreshToken (refresh-token-key) ฉันยังคงได้รับข้อผิดพลาด "invalid_grant" ฉันได้ตรวจสอบ auth-url แล้วและมีค่าเริ่มต้นเป็น "force" หากฉันเปลี่ยนเป็น "อัตโนมัติ" และเรียกใช้วิธีการตรวจสอบสิทธิ์ฉันจะไม่เปลี่ยนเส้นทางเนื่องจากฉันได้ให้สิทธิ์การเข้าถึง แต่การตอบกลับเป็น accessToken ที่ไม่มีการรีเฟรช ความคิดใด ๆ ?
seorch.me

@ seorch.me ฟังดูบ้า แต่เป็นไปได้ไหมที่คุณต้องตั้งค่า$client( $client = new apiClient();) ใหม่เพื่อใช้โทเค็นการรีเฟรช?
jk.

1
@ seorch.me คุณต้องตั้งค่า$client->setApprovalPrompt('force')และ$client->setAccessType('offline')รับโทเค็นการรีเฟรชใหม่ระหว่างการอนุญาต Google จะถือว่าคุณใช้โทเค็นการรีเฟรชแบบเดิมต่อไปโดยไม่บังคับให้ผู้ใช้อนุมัติขอบเขตการเข้าถึง
Jason

14

คำตอบที่โพสต์โดย @ 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());
}

สมบูรณ์แบบทำงานได้มาก สิ่งเดียวที่ฉันจะพูดคือคุณควรอธิบายว่าคุณต้องส่งวัตถุ json ไม่ใช่แค่โทเค็นเป็นสตริง
Oliver Bayes-Shelton

@ OliverBayes-Shelton สวัสดี ขอบคุณ. ฉันคิดว่า// setAccessToken() expects jsonเพียงพอแล้ว หรือเป็นส่วนอื่นของรหัส?
Daishi

วิธีนี้ใช้ได้ผลดีสำหรับฉัน แต่คุณรู้ไหมว่ารหัสนี้จัดการกับสถานการณ์ที่โทเค็นหมดอายุเนื่องจากการรีเฟรชโทเค็นเกินขีด จำกัด 50 ดูรายละเอียดเกี่ยวกับ 'Token Expiration' ได้ที่นี่: developers.google.com/identity/protocols/OAuth2#expiration
Bjorn

ดูเหมือนว่าเวอร์ชัน 2.0 ล่าสุดกำลังส่งคืนโทเค็นการรีเฟรชในอาร์เรย์โทเค็นการเข้าถึง ซึ่งหมายความว่าการบันทึกโทเค็นการเข้าถึงจะบันทึกโทเค็นการรีเฟรชด้วยเช่นกันเนื่องจากโทเค็นการรีเฟรชรวมอยู่ด้วย เพื่อตอบสนองต่อการที่โทเค็นการรีเฟรชกำลังจะหมดอายุฉันคาดเดาว่าจะต้องทดสอบและจัดการอย่างชัดเจน - จำไว้ว่าขีด จำกัด 50 คือ "ต่อผู้ใช้ต่อลูกค้า" นั่นคือ 50 ต่อไคลเอนต์ดังนั้นคุณจึงไม่น่าจะโดนโดยเฉพาะอย่างยิ่งถ้า คุณใช้ขอบเขตรวมเพื่อรวมโทเค็น
Brian C

8

นี่คือรหัสที่ฉันใช้ในโครงการของฉันและใช้งานได้ดี:

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;
}

6

มีปัญหาเดียวกัน สคริปต์ของฉันที่ใช้งานได้เมื่อวานนี้ด้วยเหตุผลแปลก ๆ ในวันนี้ ไม่มีการเปลี่ยนแปลง.

เห็นได้ชัดว่านี่เป็นเพราะนาฬิการะบบของฉันปิดไป 2.5 (!!) วินาทีการซิงค์กับ NTP ได้รับการแก้ไข

ดูเพิ่มเติมที่https://code.google.com/p/google-api-php-client/wiki/OAuth2#Solving_invalid_grant_errors


คำตอบนั้นช่วยฉันได้มากผู้ชาย คุณคงช่วยฉันได้มากเวลา มาก! ขอบคุณ! ฉันเพิ่งดำเนินการsudo apt-get install ntpบนเครื่อง Debian ของฉันเพื่อติดตั้ง NTP มันซิงโครไนซ์นาฬิกาและปัญหาได้รับการแก้ไข
Szymon Sadło

4

FYI: 3.0 Google Analytics API จะรีเฟรชโทเค็นการเข้าถึงโดยอัตโนมัติหากคุณมีโทเค็นการรีเฟรชเมื่อหมดอายุดังนั้นสคริปต์ของคุณจึงไม่จำเป็นต้องrefreshTokenใช้

(ดูSignฟังก์ชันในauth/apiOAuth2.php)


"รีเฟรชอัตโนมัติ" หมายความว่าฉันต้องขอ getAccessToken () แล้วฉันจะได้รับการรีเฟรชกลับมา? แต่ฉันต้องตั้งค่าโทเค็นการรีเฟรชออกจาก DB ก่อนใช่ไหม? มิฉะนั้นการรีเฟรชจะทำงานโดยไม่มีโทเค็นการรีเฟรชและฉันไม่คิดว่ามันจะได้ผล
ninsky

4

บางครั้งรีเฟรช Token $client->setAccessType ("offline");ฉันไม่ได้ถูกสร้างโดยใช้

ลองสิ่งนี้:

$client->setAccessType ("offline");
$client->setApprovalPrompt ("force"); 

เพื่อให้เจาะจงมากขึ้นดูเหมือนว่าโทเค็นการรีเฟรชจะรวมอยู่ในการอนุญาตครั้งแรกของคุณ หากคุณบันทึกแล้วใช้งานฉันเชื่อว่า (ตามที่คนอื่นไม่ได้รับการตรวจสอบ) ว่าโทเค็นการรีเฟรชยังคงถูกส่งคืน ตอนนี้ doco ยังบอกด้วยว่าพวกเขาจะรีเฟรชโทเค็นการเข้าถึงโดยอัตโนมัติหากมีโทเค็นการรีเฟรชซึ่งหมายความว่ามันเป็นเพียงเรื่องของการจัดการโทเค็นการรีเฟรชอย่างปลอดภัย setApprovalPrompt ('force') บังคับให้มีการรีเฟรชโทเค็นในภายหลัง ถ้าไม่มีคุณจะไม่ได้รับอีก
Brian C

2

ฉันใช้ตัวอย่างโดย smartcodes กับ 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>

1
ได้โปรดอธิบายฉันได้ไหมว่าทำไมบรรทัดนี้: $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];. ทำไมคุณถึงเปลี่ยนเส้นทางไปที่หน้าเดียวกัน? จำเป็นไหม
Tropicalista

@ ทรอปิคัลลิสต้า: ไม่จำเป็นต้องโหลดซ้ำหน้าต่อหน้า แต่นี่เป็นวิธีการใช้โฟลว์การตรวจสอบสิทธิ์โดยทั่วไป
John Slegers

แต่คุณไม่ได้ใช้โทเค็นการรีเฟรชเพื่อรับโทเค็นการเข้าถึงใหม่หากโทเค็นการเข้าถึงหมดอายุ
apadana

2

คุณต้องบันทึกโทเค็นการเข้าถึงลงในไฟล์หรือฐานข้อมูลเป็นสตริง json ในระหว่างการร้องขอการอนุญาตเริ่มต้นและตั้งค่าประเภทการเข้าถึงเป็นออฟไลน์ $client->setAccessType("offline")

จากนั้นในระหว่างการร้องขอ api ตามมาให้คว้าโทเค็นการเข้าถึงจากไฟล์หรือฐานข้อมูลของคุณและส่งต่อไปยังไคลเอนต์:

$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()ฟังก์ชั่นจะทำงานให้คุณและให้โทเค็นการเข้าถึงใหม่บันทึกกลับไปยังไฟล์หรือฐานข้อมูลของคุณ


1

ฉันมีปัญหาเดียวกันกับ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()));
    }

1

สิ่งนี้ได้ผลดีมากบางทีอาจช่วยใครก็ได้:

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();
}
?>

1

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);
        }
    }


}

1

ฉันใช้ google-api-php-client v2.2.2 ฉันได้รับโทเค็นใหม่ที่มีfetchAccessTokenWithRefreshToken();การเรียกฟังก์ชันโดยไม่มีพารามิเตอร์จะส่งคืนโทเค็นการเข้าถึงที่อัปเดตและโทเค็นที่รีเฟรชจะไม่สูญหาย

if ($client->getAccessToken() && $client->isAccessTokenExpired()) {
    $new_token=$client->fetchAccessTokenWithRefreshToken();
    $token_data = $client->verifyIdToken();
}    

0

ใช้ข้อมูลโค้ดต่อไปนี้เพื่อรับโทเค็นการรีเฟรชของคุณ

    <?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'];
    ?>

0

ตามการตรวจสอบสิทธิ์ใน Google: OAuth2 ยังคงส่งคืน 'invalid_grant'

"คุณควรใช้โทเค็นการเข้าถึงที่คุณได้รับซ้ำหลังจากการตรวจสอบสิทธิ์สำเร็จครั้งแรกคุณจะได้รับข้อผิดพลาด invalid_grant หากโทเค็นก่อนหน้าของคุณยังไม่หมดอายุโปรดแคชไว้ที่ใดที่หนึ่งเพื่อให้คุณสามารถใช้ซ้ำได้"

หวังว่ามันจะช่วยได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.