Google API OAuth 2.0 CURL返回“必需的参数丢失:grant_type”
我正在尝试为Web服务器应用程序实施Google的OAuth 2.0身份验证。Google API OAuth 2.0 CURL返回“必需的参数丢失:grant_type”
我可以从Google ok获得代码,但是当我发布此代码尝试获取访问令牌时,即使grant_type存在,它也会给我提供错误“必需的参数丢失:grant_type。Error 400” 。
此外,如果我指定内容长度为0以外的任何内容,则会引发其他错误。
下面是在做这个卷曲后的代码:
$url = 'https://accounts.google.com/o/oauth2/token';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FAILONERROR, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/x-www-form-urlencoded',
'Content-length: 0'
));
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
'code='. urlencode($code),
'client_id=' . urlencode($clientID),
'client_secret=' . urlencode($clientSecret),
'redirect_uri=http%3A%2F%2Flocalhost%2Fexperiments%2FnewGALogin.php',
'grant_type=authorization_code'
));
尝试
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
'code' => $code,
'client_id' => $clientID,
'client_secret' => $clientSecret,
'redirect_uri' => 'http%3A%2F%2Flocalhost%2Fexperiments%2FnewGALogin.php',
'grant_type' => 'authorization_code'
));
或
curl_setopt($ch, CURLOPT_POSTFIELDS,
'code=' . urlencode($code) . '&' .
'client_id=' . urlencode($clientID) . '&' .
'client_secret=' . urlencode($clientSecret) . '&' .
'redirect_uri=http%3A%2F%2Flocalhost%2Fexperiments%2FnewGALogin.php' . '&' .
'grant_type=authorization_code'
);
请阅读文档CURLOPT_POSTFIELDS
小心:
...与字段名的关键和现场数据的数组值
你只是做了一些,但没有。尝试:
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
'code' => $code,
'client_id' => $clientID,
...
在这种情况下,您不需要urlencode
。
我不想去相信,但奇怪的是,简单地从CURLOPT_POSTFIELDS开关从阵列的“&”连接字符串(与相同的数据!)让我的OAuth服务器最终识别grant_type。
在研究了这个问题之后,好像grant_type不被数组格式所接受。 (是的,查询字符串方法的工作原理,但它很难建立。)
如果你想保留POST字段在数组中,可以将数组http_build_query()添加到数组中。
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
'code' => $code,
'client_id' => $clientID,
'client_secret' => $clientSecret,
'redirect_uri' => 'http%3A%2F%2Flocalhost%2Fexperiments%2FnewGALogin.php',
'grant_type' => 'authorization_code'
)));
的核心问题与原来的问题和一些问题的答案是使用密钥CURLOPT_POSTFIELDS
当curl_setopt
电话接受了不同的值。
当输入是数组时,生成的Content-Type
将是multipart/form-data
,它不符合OAuth 2.0规范,服务器将忽略它。当输入是查询编码的字符串(例如使用http_build_query
构建)时,Content-Type:
将是application/x-www-form-urlencoded
,这是规范要求的。
参见“注意事项”部分:http://php.net/manual/en/function.curl-setopt.php
我试图用在这里提供的原题加答案PHP代码,并保持约一失踪“grant_type”的谷歌令牌服务器的抱怨,甚至虽然它肯定被传入。事实证明,问题是CURLOPT_HTTPHEADER不喜欢/需要'Content-length:0'。希望这个完整的工作代码可以帮助别人解决相同的问题。
// This is what Google's OAUTH server sends to you
$code = $_GET['code'];
// These come from your client_secret.json file
$clientID = "your client id.apps.googleusercontent.com";
$clientSecret = "your client secret";
$redirectURI = "your redirect URI";
$token_uri = 'https://accounts.google.com/o/oauth2/token';
$ch = curl_init($token_uri);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FAILONERROR, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/x-www-form-urlencoded'
));
// Build the URLEncoded post data
$postFields = http_build_query(array(
'client_secret' => $clientSecret,
'grant_type' => 'authorization_code',
'redirect_uri' => $redirectURI,
'client_id' => $clientID,
'code' => $code
));
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
$response = curl_exec($ch);
// Save response, especially the "refresh_token"
$pathToAccessToken = "/your/path/to/access_token.json";
file_put_contents($pathToAccessToken, $response);
仅供参考,响应JSON看起来是这样的:
{
"access_token" : "xxxWhateverGibberish",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "yyyMoreGibberish"
}
之后,我可以成功查询日历(API的范围叫我原来的OAuth请求)使用如下代码:
function getClient() {
$client = new Google_Client();
$client->setApplicationName(APPLICATION_NAME);
$client->setScopes(SCOPES);
$client->setAuthConfigFile(CLIENT_SECRET_PATH);
$client->setAccessType('offline');
// Load previously authorized credentials from a file.
$pathToAccessToken = "/your/path/to/access_token.json";
$accessToken = file_get_contents($pathToAccessToken);
$client->setAccessToken($accessToken);
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->refreshToken($client->getRefreshToken());
file_put_contents($pathToAccessToken, $client->getAccessToken());
}
return $client;
}
$client = getClient();
$service = new Google_Service_Calendar($client);
// Print the next 10 events on the user's calendar.
$calendarId = 'primary';
$optParams = array(
'maxResults' => 10,
'orderBy' => 'startTime',
'singleEvents' => TRUE,
'timeMin' => date('c'),
);
$results = $service->events->listEvents($calendarId, $optParams);
if (count($results->getItems()) == 0) {
print "No upcoming events found.\n";
} else {
print "Upcoming events:\n";
foreach ($results->getItems() as $event) {
$start = $event->start->dateTime;
if (empty($start)) {
$start = $event->start->date;
}
printf("%s (%s)\n", $event->getSummary(), $start);
}
}
您的第二个解决方案有效,谢谢:) – hud