2016-06-28 53 views
0

簡而言之,我想要在Google API上獲取帶有服務帳戶的新訪問令牌。我使用了OAuth 2.0和JWT請求。我發現了很多類似的帖子,但其中沒有人回答我的問題。我做了一切符合Google OAuth 2.0 Server-to-Server request guide,但是當我發送POST請求時,我得到了「invalid_grant」的回報。任何想法爲什麼?這裏是我的代碼:PHP Google API OAuth2 JWT對新訪問令牌的請求顯示爲「invalid_grant」

$jwt_header_array =  array( "alg"  => "RS256", 
            "typ"  => "JWT"); 

    $jwt_claim_array =  array( "iss"  => "[email protected]", 
            "scope"  => "https://www.googleapis.com/auth/drive.file", 
            "aud"  => "https://www.googleapis.com/oauth2/v4/token", 
            "exp"  => time()+3600, 
            "iat"  => time()); 

    $jwt_header = base64_encode(json_encode($jwt_header_array)); 
    $jwt_claim = base64_encode(json_encode($jwt_claim_array)); 

    $key = "-----BEGIN PRIVATE KEY----- privat_key_downloaded_from_google_console -----END PRIVATE KEY-----\n"; 

    $pkeyid = openssl_pkey_get_private($key); 
    openssl_sign($jwt_header.'.'.$jwt_claim, $jwt_signature, $pkeyid, "sha256"); 
    $jwt_signature = base64_encode($jwt_signature); 

    $jwt = $jwt_header.'.'.$jwt_claim.'.'.$jwt_signature; 

    echo $jwt.'<br /><br />'; 

    $url = 'https://www.googleapis.com/oauth2/v4/token'; 
    $query = 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion='.$jwt; 

    $ch = curl_init(); 
    curl_setopt($ch, CURLOPT_URL, $url); 
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded')); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 
    curl_setopt($ch, CURLOPT_POST, 1); 
    curl_setopt($ch, CURLOPT_POSTFIELDS, $query); 
    $result = curl_exec($ch); 

    var_dump($result); 
+0

從技術上說,您需要base64對JWT元素進行url編碼,而不僅僅是base64對它們進行編碼 –

+0

這些編碼是很好的,因爲我得到了正確的JWT頭文件,並在Google的示例中聲明瞭相同的輸入。唯一的問題是簽名,我無法驗證,因爲密鑰與示例中使用的不同。 –

回答

1

我發現了一個解決方案,它很荒唐顯而易見。爲什麼不使用Google Utils,Auth和Signer/P12類?你可以用composer(google/apiclient)獲得整個軟件包,除此之外,你需要用這個軟件來進行Google API認證(事實上,我已經有了這個軟件包,蠢人)。我將引導您完成整個過程:

新的解決方案:

您需要谷歌API包,並在舊的解決方案下面描述的谷歌服務帳戶(階段1,2,3)。從這裏只是複製粘貼的完全基於API代碼並更換輸入DATAS:

$client_email = '[email protected]'; 
$private_key = file_get_contents('p12_final.p12'); 
$scopes = array('https://www.googleapis.com/auth/drive.file'); 
$credentials = new Google_Auth_AssertionCredentials(
    $client_email, 
    $scopes, 
    $private_key 
); 

$client = new Google_Client(); 
$client->setAssertionCredentials($credentials); 
if ($client->getAuth()->isAccessTokenExpired()) { 
    $client->getAuth()->refreshTokenWithAssertion(); 
} 

老辦法:

  1. 創建Google Service account,因爲這是必不可少的訪問谷歌的API,無需進一步用戶同意。確保創建它時,檢查「提供新的私鑰」和「P12」選項。如果需要,請檢查其他選項。

  2. 下載後,將P12文件上傳到您的服務器/本地,並存儲密碼(此時通常爲「notasecret」)。

  3. 如果您還沒有安裝包含composer或GIT的Google API包,我更喜歡作曲家,因爲GIT版本缺少一些庫,對我來說客戶類有點兒錯誤(當然可能是我的錯)。

  4. 您只需使用正確的類來製作和編碼JWT標頭和playload,並簽署證書即可。請注意P12證書路徑和playload中的corrent輸入(您可以從Google Developer Console Credetials頁面獲取所有內容,並且還可以獲取有關Google OAuth 2.0 Server-to-Server Application頁面上的值的信息)。下面是代碼:

$header = array("typ" => "JWT", 
       "alg" => "RS256"); 

$playload = array( "iss"  => "[email protected]", 
        "scope"  => "https://www.googleapis.com/auth/drive.file", 
        "aud"  => "https://www.googleapis.com/oauth2/v4/token", 
        "exp"  => time()+3600, 
        "iat"  => time()); 

$segments = array(); 
$segments[] = Google_Utils::urlSafeB64Encode(json_encode($header)); 
$segments[] = Google_Utils::urlSafeB64Encode(json_encode($playload)); 
$signing_input = implode(".", $segments); 
$signer = new Google_Signer_P12(file_get_contents('p12.p12', true), 'notasecret'); 
$signature = $signer->sign($signing_input); 
$segments[] = Google_Utils::urlSafeB64Encode($signature); 
$jwt = implode(".", $segments); 
  • 發送與任何你想獲得訪問令牌捲曲或請求:
  • $url = 'https://www.googleapis.com/oauth2/v4/token'; 
    $query = 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion='.$jwt; 
    
    $ch = curl_init(); 
    curl_setopt($ch, CURLOPT_URL, $url); 
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded')); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 
    curl_setopt($ch, CURLOPT_POST, 1); 
    curl_setopt($ch, CURLOPT_POSTFIELDS, $query); 
    $result = curl_exec($ch); 
    
  • 最後,var_dump($ result)輸出應該類似:
  • string (141) 「{ 」的access_token「: 」ya29.Ci8QAzKz-U83RiaylDKgSDgH9XEVQrdBAQ5EBxMFUncN7WLfeGan0BCMJRdFJykC-G「, 」token_type「: 」承載「, 」expires_in「:3600}」

    希望你喜歡它,並會給予好評,因爲我搞砸了用這個認證故事2天。在某些情況下,Google API可以做到魔術,所以學習inmho是一件非常重要的事情。

    相關問題