Php Google API OAuth 2.0“返回”;缺少必需的参数:grant“U type”;
我正在尝试为web服务器应用程序实现Google的OAuth2.0身份验证 我可以从Google ok获得代码,但当我发回此代码以尝试获取访问令牌时,它总是给我错误“缺少必需参数:grant_类型。错误400”,即使grant_类型存在 另外,如果我将内容长度指定为0以外的任何值,则会引发其他错误 下面是做这篇文章的代码:Php Google API OAuth 2.0“返回”;缺少必需的参数:grant“U type”;,php,curl,oauth,google-api,Php,Curl,Oauth,Google Api,我正在尝试为web服务器应用程序实现Google的OAuth2.0身份验证 我可以从Google ok获得代码,但当我发回此代码以尝试获取访问令牌时,它总是给我错误“缺少必需参数:grant_类型。错误400”,即使grant_类型存在 另外,如果我将内容长度指定为0以外的任何值,则会引发其他错误 下面是做这篇文章的代码: $url = 'https://accounts.google.com/o/oauth2/token'; $ch = curl_init($url); curl_setop
$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,
...
在这种情况下,您不需要urlencode
。试试看
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'
));
或
我不想相信这一点,但奇怪的是,只需将CURLOPT_POSTFIELDS从数组切换到“&”串联字符串(使用相同的数据!)就可以让我的OAuth服务器最终识别grant_类型。在研究了这个问题后,数组格式中似乎不接受grant_类型。(是的,查询字符串方法可以工作,但构建起来很麻烦。) 如果您希望将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\u POSTFIELDS
时在CURLOPT\u setopt
调用中接受的不同值
当输入为数组时,生成的内容类型
将是多部分/表单数据
,这不符合OAuth 2.0规范,服务器将忽略它。当输入是查询编码字符串(例如使用http\u build\u query
构建)时,内容类型:
将是application/x-www-form-urlencoded
,这是规范要求的
请参阅:的“注释”部分,我试图使用此处提供的原始问题和答案中的PHP代码,并不断收到Google token服务器关于缺少“grant_类型”的投诉,尽管它肯定是被传入的。原来问题是CURLOPT_HTTPHEADER不喜欢/不需要“内容长度: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"
}
之后,我可以使用如下代码成功地查询日历(原始OAuth请求调用的API范围):
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);
}
}
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);
}
}