2016-06-28 158 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是一件非常重要的事情。