Làm cách nào để làm mới mã thông báo với ứng dụng khách API của Google?


91

Tôi đã thử với API Google Analytics (V3) và đã gặp phải lỗi som. Thứ nhất, mọi thứ được thiết lập chính xác và hoạt động với tài khoản thử nghiệm của tôi. Nhưng khi tôi muốn lấy dữ liệu từ một ID hồ sơ khác (Cùng một tài khoản Google Accont / GA), tôi gặp phải Lỗi 403. Điều kỳ lạ là dữ liệu từ một số tài khoản GA sẽ trả về dữ liệu trong khi các tài khoản khác tạo ra lỗi này.

Tôi đã thu hồi mã thông báo và xác thực một lần nữa, và bây giờ có vẻ như tôi có thể lấy dữ liệu từ tất cả các tài khoản của mình. Vấn đề được giải quyết? Không phải. Vì khóa truy cập sẽ hết hạn, tôi sẽ gặp lại vấn đề tương tự.

Nếu tôi đã hiểu mọi thứ đúng, người ta có thể sử dụng resfreshToken để lấy một xác thực mới.

Vấn đề là, khi tôi chạy:

$client->refreshToken(refresh_token_key) 

lỗi sau được trả về:

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

Tôi đã kiểm tra mã đằng sau phương thức refreshToken và theo dõi yêu cầu trở lại tệp “apiOAuth2.php”. Tất cả các thông số được gửi chính xác. Grant_type được mã hóa cứng thành 'refresh_token' trong phương thức, vì vậy tôi khó hiểu có chuyện gì không ổn. Mảng tham số trông như thế này:

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

Thủ tục như sau.

$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

Đây là một lỗi, hay tôi đã hoàn toàn hiểu nhầm điều gì đó?


Không biết đó là lỗi hay gì đó nhưng tôi hiện đang làm mới mã thông báo truy cập bằng cách sử dụng yêu cầu http CURL thô và nó hoạt động tốt.
gremo

Seorch ... bạn tìm ra cái này chưa? Vấn đề tương tự ở đây.
Brian Vanderbusch

@gremo bạn có thể chia sẻ yêu cầu http CURL thô mà bạn đã sử dụng ở đây không? Sẽ thực sự hữu ích. Cảm ơn!
Silver Ringvee vào

Câu trả lời:


76

Vì vậy, cuối cùng tôi đã tìm ra cách làm điều này. Ý tưởng cơ bản là bạn có mã thông báo mà bạn nhận được trong lần đầu tiên yêu cầu xác thực. Mã thông báo đầu tiên này có mã thông báo làm mới. Mã thông báo gốc đầu tiên sẽ hết hạn sau một giờ. Sau một giờ, bạn phải sử dụng mã làm mới từ mã thông báo đầu tiên để nhận mã thông báo có thể sử dụng mới. Bạn sử dụng $client->refreshToken($refreshToken)để lấy mã thông báo mới. Tôi sẽ gọi đây là "mã thông báo tạm thời". Bạn cũng cần lưu trữ mã thông báo tạm thời này vì sau một giờ nó cũng hết hạn và lưu ý rằng nó không có mã thông báo làm mới được liên kết với nó. Để có được mã thông báo tạm thời mới, bạn cần sử dụng phương pháp bạn đã sử dụng trước đó và sử dụng mã làm mới của mã thông báo đầu tiên. Tôi có mã đính kèm bên dưới, nó là xấu, nhưng tôi mới ở đây ...

//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
Thay vì kiểm tra cho 3600 giây, bạn nên sử dụng $ khách hàng-> isAccessTokenExpired ()
Gaurav Gupta

2
Cập nhật nhỏ. Trong phiên bản mới nhất, khi bạn yêu cầu mã thông báo làm mới, mã thông báo truy cập mới được trả lại hiện đi kèm với mã làm mới mới. Vì vậy, về cơ bản, bạn có thể sử dụng mã thông báo json đã cập nhật để thay thế mã thông báo json trước đó và không cần giữ lại mã thông báo truy cập ban đầu nữa. .
skidadon

1
Lưu ý rằng $client->isAccessTokenExpired()sẽ vẫn chỉ kiểm tra thời gian được giữ cục bộ để xem liệu nó có nghĩ rằng mã thông báo đã hết hạn hay không. Mã thông báo có thể vẫn đã hết hạn và ứng dụng cục bộ sẽ chỉ thực sự biết khi cố gắng sử dụng nó. Trong trường hợp này, ứng dụng khách API sẽ trả về một ngoại lệ và sẽ không tự động làm mới mã thông báo.
Jason

44

Vấn đề là ở mã làm mới:

[refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

Khi một chuỗi có dấu '/'get json encoded, Nó được thoát bằng dấu '\', do đó bạn cần phải loại bỏ nó.

Mã làm mới trong trường hợp của bạn phải là:

1/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

Những gì tôi giả sử bạn đã làm là bạn đã in chuỗi json mà google đã gửi lại và sao chép và dán mã thông báo vào mã của bạn bởi vì nếu bạn làm json_decodenhư vậy thì nó sẽ xóa chính xác '\'cho bạn!


1
đề cập tuyệt vời, làm cho ngày của tôi! giờ đã tiết kiệm!
Mircea Sandu

Bạn đã cứu ngày của tôi!
Trương Đăng

Tôi ước tôi có thể ủng hộ điều này 100 lần. Tôi đã chuẩn bị tạo một lỗ hổng trên tường với bàn phím của mình sau khi nhìn chằm chằm vào thông báo "bad Grant" trong vài giờ sau khi cố gắng hoàn toàn mọi thứ để làm cho mã thông báo hoạt động. Fricking google man, tại sao sử dụng dấu gạch chéo, chỉ tại sao?
Askerman

18

đây là đoạn mã để đặt mã thông báo, trước đó hãy đảm bảo rằng loại truy cập phải được đặt thành ngoại tuyến

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

Để làm mới mã thông báo

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

điều này sẽ làm mới mã thông báo của bạn, bạn phải cập nhật nó trong phiên để bạn có thể làm

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

1
bạn đã làm cho tôi một ngày với điều này :) cảm ơn bạn rất nhiều, đơn giản hơn tôi nghĩ rất nhiều vì tôi đã dành rất nhiều thời gian để không đi đến đâu: D
TB Ygg

16

Loại truy cập phải được đặt thành offline. statelà một biến bạn đặt để sử dụng cho riêng mình, không phải cho API.

Đảm bảo rằng bạn có phiên bản mới nhất của thư viện khách hàng và thêm:

$client->setAccessType('offline');

Xem Tạo URL để biết giải thích về các tham số.


Cảm ơn jk. Tôi đã tải xuống phiên bản mới nhất và thu hồi quyền truy cập vào ứng dụng cho tài khoản của mình. Sau đó, tôi cấp quyền truy cập một lần nữa và lưu trữ accessToken và refreshToken. Vấn đề là, tôi luôn nhận được refreshToken, ngay cả khi setAccessType đã bị bỏ qua. Nhưng dù sao, khi tôi chạy $ client-> refreshToken (refresh-token-key), tôi vẫn gặp lỗi "invalid_grant". Tôi đã kiểm tra url auth và nó được mặc định là "buộc". Nếu tôi thay đổi nó thành "tự động" và chạy phương thức xác thực, tôi sẽ không được chuyển hướng vì tôi đã cấp quyền truy cập. Nhưng phản hồi là một accessToken mà không cần làm mới. Bất kỳ ý tưởng?
seorch.me

@ seorch.me Nghe có vẻ điên rồ nhưng có khả năng bạn phải thiết lập một $client( $client = new apiClient();) mới để sử dụng mã làm mới không?
jk.

1
@ seorch.me bạn phải đặt $client->setApprovalPrompt('force')cũng như $client->setAccessType('offline')nhận mã làm mới mới trong quá trình ủy quyền. Không buộc người dùng phê duyệt phạm vi truy cập, Google giả định rằng bạn sẽ tiếp tục sử dụng mã làm mới cũ.
Jason

14

Câu trả lời được đăng bởi @ uri-weg phù hợp với tôi nhưng vì tôi không tìm thấy lời giải thích của anh ấy rõ ràng lắm, hãy để tôi diễn đạt lại nó một chút.

Trong chuỗi quyền truy cập đầu tiên, trong lệnh gọi lại, khi bạn đến điểm bạn nhận được mã xác thực, bạn cũng phải lưu mã thông báo truy cập và mã làm mới .

Lý do là google api chỉ gửi cho bạn mã thông báo truy cập với mã làm mới khi nhắc cấp quyền truy cập. Các mã thông báo truy cập tiếp theo sẽ được gửi mà không có bất kỳ mã làm mới nào (trừ khi bạn sử dụng approval_prompt=forcetùy chọn).

Mã thông báo làm mới bạn nhận được lần đầu tiên vẫn hợp lệ cho đến khi người dùng thu hồi quyền truy cập.

Trong php đơn giản, một ví dụ về chuỗi gọi lại sẽ là:

// 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']);

Và sau này, trong php đơn giản, trình tự kết nối sẽ là:

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

hoàn hảo, đã làm việc rất nhiều. chỉ có điều tôi muốn nói là bạn nên giải thích rằng bạn cần truyền đối tượng json không chỉ mã thông báo dưới dạng một chuỗi.
Oliver Bayes-Shelton

@ OliverBayes-Shelton Xin chào. Cảm ơn. Tôi nghĩ // setAccessToken() expects jsonlà đủ. Hay nó dành cho một phần khác của mã?
Daishi

Điều này rất hiệu quả đối với tôi, nhưng bạn có biết mã này có xử lý được các tình huống trong đó mã thông báo hết hạn do vượt quá giới hạn 50 lần làm mới mã thông báo không? Thông tin chi tiết về 'Hết hạn mã thông báo' có thể được tìm thấy tại đây: developer.google.com/identity/protocols/OAuth2#expiration
Bjorn vào

Có vẻ như phiên bản 2.0 mới nhất hiện đang trả lại mã thông báo làm mới trong mảng mã thông báo truy cập. Điều này có nghĩa là lưu mã thông báo truy cập cũng lưu mã làm mới, vì mã làm mới được bao gồm. Để phản hồi về việc mã thông báo làm mới hết hạn, tôi đoán rằng điều đó sẽ phải được kiểm tra và xử lý rõ ràng - hãy nhớ giới hạn 50 là "mỗi người dùng trên mỗi khách hàng", tức là 50 trên mỗi khách hàng, vì vậy bạn không chắc sẽ đạt được nó, đặc biệt nếu bạn sử dụng phạm vi bao gồm để kết hợp các mã thông báo.
Brian C

8

Đây là mã mà tôi đang sử dụng trong dự án của mình và nó đang hoạt động tốt:

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

Có cùng một vấn đề; kịch bản của tôi hoạt động ngày hôm qua, vì một số lý do kỳ lạ đã không hoạt động hôm nay. Không thay đổi.

Rõ ràng điều này là do đồng hồ hệ thống của tôi đã tắt 2,5 (!!) giây, đồng bộ hóa với NTP đã khắc phục sự cố này.

Xem thêm: https://code.google.com/p/google-api-php-client/wiki/OAuth2#Solving_invalid_grant_errors


Câu trả lời đó đã giúp tôi rất nhiều, anh bạn. Bạn có lẽ đã tiết kiệm cho tôi rất nhiều thời gian. Rất nhiều! Cảm ơn! Tôi vừa thực thi sudo apt-get install ntptrên máy Debian của mình để cài đặt NTP. Nó đã đồng bộ hóa đồng hồ và vấn đề đã được giải quyết.
Szymon Sadło

4

FYI: API Google Analytics 3.0 sẽ tự động làm mới mã thông báo truy cập nếu bạn có mã làm mới khi nó hết hạn, vì vậy tập lệnh của bạn không bao giờ cần refreshToken.

(Xem Signchức năng trong auth/apiOAuth2.php)


"Tự động làm mới" có nghĩa là tôi chỉ cần yêu cầu getAccessToken () và tôi sẽ nhận được một làm mới trở lại? Nhưng tôi phải đặt mã thông báo làm mới ra khỏi DB trước, phải không? Nếu không, quá trình làm mới sẽ hoạt động mà không có mã thông báo làm mới và tôi không nghĩ điều này sẽ hoạt động
ninsky

4

Đôi khi tôi không tạo Mã thông báo làm mới bằng cách sử dụng $client->setAccessType ("offline");.

Thử cái này:

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

Để cụ thể hơn, có vẻ như mã thông báo Làm mới được bao gồm trong ủy quyền đầu tiên của bạn . Nếu bạn lưu và sau đó sử dụng nó, tôi tin rằng (theo những người khác, chưa được xác minh) rằng mã thông báo làm mới tiếp tục được trả lại. Doco hiện cũng nói rằng họ sẽ tự động làm mới mã thông báo truy cập nếu họ có mã thông báo làm mới, có nghĩa là đó chỉ đơn giản là vấn đề quản lý mã làm mới một cách an toàn. setApprovalPrompt ('force') buộc mã làm mới được phát hành sau đó; không có nó bạn sẽ không nhận được một cái khác.
Brian C

2

Tôi đã sử dụng ví dụ bằng mã thông minh với phiên bản hiện tại của Google API, nhưng cái đó không hoạt động. Tôi nghĩ rằng API của anh ấy đã quá lỗi thời.

Vì vậy, tôi vừa viết phiên bản của riêng mình, dựa trên một trong các ví dụ API ... Nó xuất ra mã thông báo truy cập, mã thông báo yêu cầu, loại mã thông báo, mã thông báo ID, thời gian hết hạn và thời gian tạo dưới dạng chuỗi

Nếu thông tin đăng nhập khách hàng và khóa nhà phát triển của bạn chính xác, thì mã này sẽ hoạt động hiệu quả.

<?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
Xin vui lòng, bạn có thể giải thích cho tôi tại sao dòng này: $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];. Tại sao bạn chuyển hướng đến cùng một trang? điều này có cần thiết không?
Tropicalista

@Tropicalista: Không cần thiết phải tải lại trang, nhưng đây là cách các luồng xác thực thường được triển khai.
John Slegers

nhưng bạn không sử dụng mã làm mới để nhận mã truy cập mới nếu mã thông báo truy cập hết hạn.
apadana

1

Tôi gặp sự cố tương tự với google / google-api-php-client v2.0.0-RC7 và sau khi tìm kiếm trong 1 giờ, tôi đã giải quyết được sự cố này bằng cách sử dụng json_encode như sau:

    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

Điều này ở đây hoạt động rất tốt, có thể nó có thể giúp bất kỳ ai:

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 đã thực hiện một số thay đổi kể từ khi câu hỏi này được đăng ban đầu.

Đây là ví dụ hiện đang làm việc của tôi.

    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

Tôi sử dụng google-api-php-client v2.2.2 Tôi nhận được mã thông báo mới với fetchAccessTokenWithRefreshToken();lệnh gọi hàm if mà không có tham số, nó trả về mã thông báo truy cập cập nhật và mã được làm mới không bị mất.

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

1

Bạn cần lưu mã thông báo truy cập vào tệp hoặc cơ sở dữ liệu dưới dạng chuỗi json trong yêu cầu ủy quyền ban đầu và đặt loại truy cập thành ngoại tuyến $client->setAccessType("offline")

Sau đó, trong các yêu cầu api tiếp theo, hãy lấy mã thông báo truy cập từ tệp hoặc db của bạn và chuyển nó cho máy khách:

$accessToken = json_decode($row['token'], true);
$client->setAccessToken($accessToken);

Bây giờ bạn cần kiểm tra xem mã thông báo đã hết hạn chưa:

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

Các fetchAccessTokenWithRefreshToken()chức năng sẽ làm việc cho bạn và cung cấp một mã thông báo truy cập mới, tiết kiệm nó trở lại tập tin hoặc cơ sở dữ liệu của bạn.


0

Theo Xác thực trên google: OAuth2 tiếp tục trả về 'invalid_grant'

"Bạn nên sử dụng lại mã thông báo truy cập bạn nhận được sau lần xác thực thành công đầu tiên. Bạn sẽ gặp lỗi không hợp lệ nếu mã thông báo trước đó của bạn chưa hết hạn. Hãy lưu vào bộ nhớ cache ở đâu đó để bạn có thể sử dụng lại."

hy vọng nó giúp


-1

sử dụng đoạn mã sau để nhận mã thông báo làm mới của bạn

    <?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'];
    ?>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.