2012-06-14 94 views
1

我正在爲存儲API創建API請求(GET存儲桶),並且其中一個必需參數是「授權」標頭。使用服務帳戶爲Google Cloud Storage REST API請求OAuth2訪問令牌時發生invalid_grant錯誤

請注意,我用的是服務帳戶訪問API。

我跟着文檔https://developers.google.com/accounts/docs/OAuth2ServiceAccount獲得的「授權」標頭的訪問令牌,這樣我就可以發送授權的請求給他們的REST API。問題是我總是得到「invalid_grant」錯誤。

使用此代碼檢查出來:

<?php 
error_reporting(E_ERROR); 

const CLIENT_ID = 'XXXXXXXXXXXX.apps.googleusercontent.com'; 
const SERVICE_ACCOUNT = '[email protected]'; 
const KEY_FILE = 'XXX.p12'; 

function get_oauth_access_token() 
{ 
    $header[alg] = 'RS256'; 
    $header[typ] = 'JWT'; 

    $header = urlencode(base64_encode(utf8_encode(json_encode($header)))); 

    $assertion_time = time(); 

    $claim[iss] = CLIENT_ID; //also tried SERVICE_ACCOUNT here, no improvement 
    $claim[scope] = 'https://www.googleapis.com/auth/devstorage.read_only'; 
    $claim[aud] = 'https://accounts.google.com/o/oauth2/token'; 
    $claim[exp] = $assertion_time + 3600; 
    $claim[iat] = $assertion_time; 

    $claim = urlencode(base64_encode(utf8_encode(json_encode($claim)))); 

    $data = $header . '.' . $claim; 

    $p12 = file_get_contents(KEY_FILE); 
    $cert = array(); 
    openssl_pkcs12_read($p12, $cert, 'notasecret'); 
    $priv_key_id = openssl_get_privatekey($cert[pkey]); 

    openssl_sign($data, $signature, $priv_key_id, 'sha256'); 

    $signature = urlencode(base64_encode($signature)); 

    $assertion = $data . '.' . $signature; 

    $ch = curl_init(); 
    curl_setopt($ch, CURLOPT_URL, 'https://accounts.google.com/o/oauth2/token'); 
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 
    curl_setopt($ch, CURLOPT_POST, true); 
    curl_setopt($ch, CURLOPT_POSTFIELDS, array('grant_type'=>'assertion', 
               'assertion_type'=>'http://oauth.net/grant_type/jwt/1.0/bearer', 
               'assertion'=>$assertion)); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 


    $result = curl_exec($ch); 
    $error = curl_error($ch); 

    curl_close($ch); 
    var_dump($result); 
    var_dump($error); 
} 

get_oauth_access_token(); 

有什麼不對這段代碼中導致「invalid_grant」的錯誤?

回答

0

這裏的說明使用與谷歌雲存儲的RESTful HTTP接口的服務帳戶的一個簡單的PHP程序。我用一個服務帳戶測試了這個代碼,它似乎工作正常。如果您還有其他問題,請告訴我。

<?php 

require_once 'apiClient.php'; 

// Define constants. 
const CLIENT_ID = 'YOUR_CLIENT_ID_GOES_HERE'; 
const SERVICE_ACCOUNT_NAME = 'YOUR_SERVICE_ACCOUNT_NAME_GOES_HERE'; 
const KEY_FILE = 'key.p12'; 
const BUCKET = 'marc-us'; 

// Obtain OAuth 2.0 access token for service account. 
$client = new apiClient(); 
$key = file_get_contents(KEY_FILE); 
$client->setAssertionCredentials(new apiAssertionCredentials(
    SERVICE_ACCOUNT_NAME, 
    array('https://www.googleapis.com/auth/devstorage.full_control'), 
    $key) 
); 
$client::$auth->refreshTokenWithAssertion(); 
$json = $client->getAccessToken(); 
$accessToken = json_decode($json)->access_token; 

// Add access token to Authorization header of HTTP request. 
$ch = curl_init('http://commondatastorage.googleapis.com/' . BUCKET); 
curl_setopt($ch, CURLOPT_HTTPHEADER, 
      array('Authorization: OAuth ' . $accessToken)); 
$resp = curl_exec($ch); 
curl_close($ch); 

// Display results. 
print '<h2>Response:</h2><pre>' . $resp . '</pre>'; 
?> 
+0

不,這是行不通的,因爲我已經在這裏說: https://groups.google.com/forum/?fromgroups#!topic/gs-discussion/3y_2XVE2q7U 你建議的代碼可能只是一個解決方法,並增加了膨脹,這需要SDK才能獲得訪問令牌。 –

0

在我最後的響應代碼工作正常,我所以我懷疑你面對的環境問題。無論如何,我諮詢了Google PHP客戶端庫的所有者,他提供了一種刷新訪問令牌的更好方法,而無需調用內部的refreshTokenWithAssertion()方法。他建議這種技術:根據需要

$req = new apiHttpRequest(YOUR_URL); 
    $val = $client->getIo()->authenticatedRequest($req); 

到authenticatedRequest()的調用需要(如果他們設定斷言憑證)刷新訪問令牌的照顧。我修改了上面的代碼來使用這種方法,它對我來說工作正常。請注意,舊版本和新版本都適用於我,因此沒有功能差異,但我認爲新版本更好,因爲它避免了內部調用,使用Google PHP客戶端庫代替curl執行請求,並且結果更短,更簡單的代碼。

<?php 

require_once 'apiClient.php'; 

// Define constants. 
const SERVICE_ACCOUNT_NAME = 'YOUR_SERVICE_ACCOUNT_NAME'; 
const KEY_FILE = 'key.p12'; 
const BUCKET = 'marc-us'; 

// Obtain service account credentials assertion. 
$client = new apiClient(); 
$key = file_get_contents(KEY_FILE); 
$client->setAssertionCredentials(new apiAssertionCredentials(
    SERVICE_ACCOUNT_NAME, 
    array('https://www.googleapis.com/auth/devstorage.full_control'), 
    $key) 
); 

// Create HTTP request, authorize and execute. 
$req = new apiHttpRequest('http://commondatastorage.googleapis.com/' . BUCKET); 
$resp = $client::getIo()->authenticatedRequest($req); 

// Display results. 
print '<h2>Response:</h2>' . $resp->getResponseBody(); 

?> 
2

您的問題可能是您的服務器的時間。

我面臨着谷歌分析一個問題:我的代碼是正確的,但與谷歌的時間比我的服務器的時間有幾秒鐘的未來。您可以將服務器的時間延遲幾分鐘來進行測試。

如果一切正常,你可以使用NTP例如,保持服務器時鐘正確。

0

我有同樣的錯誤,但與Java。我的問題是exp和iat在幾秒鐘內的時間是在格林威治標準時間-5,而谷歌谷歌認證是在格林尼治標準時間。然後我將時間更改爲GMT值,一切正常。

相關問題