我正在编写一个PHP应用程序,允许用户将某些事件添加到私有Google Calendar。日历归我所有,我需要一种方法让PHP使用固定凭据与日历API通信(每个人都可以使用网站上的表单添加事件,但日历本身不公开可见)。
从我所读到的,这是可能的使用ClientLogin在v1 API。然而,在v3 API中,可用的选项是OAuth2.0或API密钥。使用API密钥似乎不起作用,因为它只能用于不需要授权的请求,而且OAuth似乎也不对,因为用户不应该访问他们自己的日历,而是我的应用程序使用的日历。
我想以编程方式获得OAuth令牌,但这迟早会破裂,因为OAuth对话框可以使用验证码。
这似乎是一个标准的用例——一个让用户以一些预定义的方式与单个日历交互的web应用程序——但是我找不到任何关于如何在v3 API中实现它的文档。有人能帮我吗?
我找到了一个解决方案,我认为这是你想要做的"官方"。
首先,你必须激活一个Google API"已安装应用程序的客户端ID"。
进入Google API控制台并创建项目。
然后,激活日历。
进入"API访问"选项,并使用"创建OAuth 2.0客户端"按钮。
给产品起一个名字(如果你愿意,还可以有一个标志)。单击"下一步"。
选择"Installed application"选项,点击"Create Client Id"。
现在您已经配置了访问权限。现在,您需要一些代码。获取方法:
*"认证码"。要获取它,您需要以下信息:
SCOPE: https://www.google.com/calendar/feeds/(如果你想访问日历API。还有其他的(你可以在OAuth 2.0 Playground找到它们)
CLIENT_ID:您将在Google API控制台的API访问部分找到它。
REDIRECT_URI: Get it at same place.
现在,将以下代码复制到一个文件中,将值放入变量中,执行代码(php -q script_name.php),并转到打印的URL。
<?php
$scope = '';
$client_id = '';
$redirect_uri = '';
$params = array(
'response_type' => 'code',
'client_id' => $client_id,
'redirect_uri' => $redirect_uri,
'scope' => $scope
);
$url = 'https://accounts.google.com/o/oauth2/auth?' . http_build_query($params);
echo $url."'n";
?>
网页将询问您是否允许访问。这样做,你会得到一个代码,这是你的认证代码。
*"刷新代码"。要获取它,您需要:
您之前使用的数据,加上API控制台中"客户端秘密"代码,介于"客户端id"answers"重定向URI"之间。
与前面一样,复制以下代码,并将变量放在适当的位置(代码字段是Authentication code)。执行,结果是"刷新令牌"。<?php
$url = 'https://accounts.google.com/o/oauth2/token';
$post_data = array(
'code' => '',
'client_id' => '',
'client_secret' => '',
'redirect_uri' => '',
'grant_type' => 'authorization_code',
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
$token = json_decode($result);
echo $token->refresh_token . "'n";
?>
在这一刻,你拥有你所需要的一切。如果有一天您更改了身份验证码,请小心。你得换新钥匙了。
访问日历服务,示例如下:在使用变量之前更改变量值。本例获取主日历事件,但您可以在日历API中更改任何事件的地址(http://code.google.com/intl/ca/apis/calendar/v3/getting_started.html#background_operations)
<?php
$scope = 'https://www.google.com/calendar/feeds/';
$client_id = '';
$client_secret = '';
$redirect_uri = '';
$refresh_token = '';
$token_url = 'https://accounts.google.com/o/oauth2/token';
$post_data = array(
'client_secret' => $client_secret,
'grant_type' => 'refresh_token',
'refresh_token' => $refresh_token,
'client_id' => $client_id
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $token_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
$token_object = json_decode($result);
$access_token = $token_object->access_token;
// Get the results
$rest_url = 'https://www.googleapis.com/calendar/v3/calendars/primary/events';
$header = "Authorization: OAuth " . $access_token;
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, array($header));
curl_setopt($ch, CURLOPT_URL, $rest_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$rest_result = curl_exec($ch);
print_r(json_decode($rest_result));
?>
首先,脚本请求"访问令牌",该令牌的有效期为一小时。然后,脚本获取REST服务(日历范围内的任何服务),在消息头中发送访问令牌。为了在脚本上提供最佳速度,最好将访问令牌存储在缓存中,直到它超过3600秒。这样,脚本将避免两个调用中的一个。
提示:
访问OAuth 2.0 Playground来了解OAuth进程中发送的所有信息。这对我帮助很大
Eric Nagel在他的博客上的一篇文章给了我解决办法。所有的功劳都归他。我不能链接,因为我没有足够的"声望"您需要同时使用开发人员密钥(API密钥)和OAuth2。开发人员密钥用于验证谁编写了软件,并用于诸如配额之类的事情,配额以每个开发人员为基础,而不是以每个用户为基础。OAuth2用于用户身份验证,需要访问非公共日历。
OAuth2有一个更新令牌,您可以从中生成会话令牌,这意味着您不需要通过屏幕抓取OAuth屏幕来获得身份验证。为此,我将编写一个小命令行应用程序,或者使用一个PHP页面。
- 在Google Api Console下转到Api Access
- 生成一个新的客户端ID并选择Installed Application(因为您将对您的服务器进行身份验证,而不是作为您的用户)
- 使用控制台应用程序或一次性PHP页面使用OAuth和您的google帐户(您想要访问的日历)进行身份验证 在身份验证的返回中应该有一个更新令牌(称为renew或refresh或类似的东西)。保存此字符串,并使其可用于PHP站点。
- 当你需要访问服务时,你的OAuth库应该有一个renew/refresh调用。下面是一个使用。net的例子。
private IAuthorizationState CreateAuthorization(NativeApplicationClient arg)
{
// Get the auth URL:
IAuthorizationState state = new AuthorizationState(new[] { AdsenseService.Scopes.AdsenseReadonly.GetStringValue() });
state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);
if (refreshToken.IsNotNullOrEmpty()) // refreshToken you stored in step 4
{
try
{
state.RefreshToken = refreshToken;
if (arg.RefreshToken(state)) // This is calling out to the OAuth servers with the refresh token getting back a session token, returns true if successful.
{
if (state.RefreshToken != refreshToken) // if the refresh token has changed, save it.
{
PersistRefreshToken(authorization.RefreshToken);
}
return this.authorization = state; // Retain the authorization state, this is what will authenticate your calls.
}
}
catch (ProtocolException ex) {...}
现在已经更新的AuthorisationState可以用来验证对API的调用。此状态可以多次使用,直到它过期,然后可以刷新。由于您是以您自己而不是用户身份对应用程序进行身份验证,因此您的所有会话都可以共享此AuthorisationState。当前AuthorisationState和刷新令牌都应该安全地保存在您的服务器上,并且永远不会发送到客户端,如果您将这些作为响应的一部分发送,您的客户端将具有与您的代码应用程序相同的特权
也可以与Google php库一起使用。$client->setAccessToken()
函数的访问令牌必须按以下方式格式化:
$at= '{"access_token":"' . $access_token . '",' .
'"token_type":"Bearer",' .
'"expires_in":3600,' .
'"refresh_token":"' . $refresh_token . '",',
'"created":' . time() . '}';
其中$access_token
为您找到的访问令牌,$refresh_token
为刷新令牌。使用无用的simple.php google示例进行测试。
验证就是:
$client->setAccessToken($at);