Google Data Protocol 客户端库中的 OAuth

警告:此页面介绍的是 Google 的旧版 API(即 Google Data API),仅适用于Google Data API 目录中列出的 API,其中许多 API 已被更新的 API 取代。如需了解特定新 API,请参阅相应新 API 的文档。如需了解如何使用较新的 API 授权请求,请参阅 Google 账号身份验证和授权

本文档介绍了如何使用 Google Data API 客户端库连接到 Google 的 OAuth 网页应用身份验证

OAuth 接口允许基于 Web 的应用代表用户访问 Google 服务。为了保持高安全性,OAuth 可让应用获取访问令牌,而无需处理用户的账号登录信息。

Google Data API 客户端库提供了一些方法,可帮助您在 Web 应用中使用 OAuth。具体而言,有用于构建获取请求令牌、授权请求令牌以及将授权的请求令牌交换为访问令牌的方法。这些库还会在向 Google Data 服务发出请求时处理必要的签名算法。

受众群体

本文档面向希望使用 Google Data API 客户端库让其基于 Web 的应用代表用户访问 Google 服务的程序员。

本文档假定您熟悉 OAuth 接口以及将 OAuth 纳入 Web 应用的一般流程。如需详细了解 OAuth 的协议,请参阅 OAuth Authentication for Web Applications(针对 Web 应用的 OAuth 身份验证)或 oauth.net 上的官方规范。

在不使用客户端库的情况下使用三方 OAuth 和 Google Data API

如果您希望 Web 应用使用 OAuth 作为授权方法与 Google Data 服务互动,那么您需要了解的所有信息都在适用于 Web 应用的 OAuth 身份验证中。 如果您不想使用 Google Data API 客户端库,则无需使用。

以下是应用可能使用 OAuth 对用户进行身份验证的流程概要:

  1. 您的应用会向 OAuthRequestToken 端点发出签名请求,以获取初始 OAuth 请求令牌。
  2. 您的应用会将用户重定向到相应的 OAuthAuthorizeToken 网址,以授权请求令牌。
  3. 用户授予访问权限后,系统会将其重定向回您的应用 (oauth_callback 网址)
  4. 您的应用会使用 OAuthGetAccessToken 端点发送签名请求,以将授权的请求令牌升级为访问令牌。

Google Data API 客户端库可为您处理各种详细信息,从而简化此授权流程。本文档将介绍具体操作方法。

注册 Web 应用

OAuth 要求所有 API 调用都必须进行数字签名。Google 支持 HMAC-SHA1RSA-SHA1 签名方法。为了对请求进行签名,您的应用首先需要向 Google 注册。注册完成后,Google 会为您提供一个使用方密钥(以及一个与 HMAC-SHA1 搭配使用的密钥),并提供一个用于上传公开证书的位置。

1. 注册网域

请按照注册基于 Web 的应用中所述的步骤操作。

2. 创建私钥 / 公共证书对(可选)

如果您选择使用 RSA-SHA1 作为 oauth_signature_method,则需要创建自签名 RSA 私钥和公钥证书对。如需查看相关示例,请参阅下文中的生成自签名私钥和公共证书

使用三方 OAuth 和 Google Data API:客户端库示例

以下各部分展示了如何使用 Google Data API 客户端库方法来遵循 OAuth 文档的“使用 OAuth”部分中概述的步骤。本文档中的所有示例均假定您的应用宿主网域为 example.com

确定数据访问权限范围

每项 Google 服务都会定义一个 scope 值,用于确定令牌对用户数据的访问权限。Google 数据常见问题解答中列出了可用的范围值。例如,如需使用 Documents List API,请将 scope 设置为 https://docs.google.com/feeds/,如常见问题解答中所列。

注意:请将 scope 值设置为允许您所需访问权限的最窄网址。这样可以降低意外获取和泄露个人数据的可能性。例如,如果您想访问当前用户的私密文档列表 Feed,请使用范围 https://docs.google.com/feeds/default/private/full,而不是范围更广的 https://docs.google.com/feeds/(该范围可提供对所有文档列表 Feed 的访问权限)。

多范围令牌

如需创建可访问多个 Google Data API 的令牌,请使用空格字符分隔各个范围。以下示例创建了一个令牌,该令牌可访问用户的 Google 文档和 Google 日历数据。

scope=https://www.google.com/calendar/feeds/ https://docs.google.com/feeds/
网址编码

网址中出现的非 ASCII 字符(包括英文冒号、斜线和空格)必须经过 网址 编码,才能通过 HTTP 传输。Google Data API 客户端库会自动对参数进行网址编码,因此您只需在为参数分配值时使用未进行网址编码的字符串即可。例如,您可以在代码中进行以下分配:

scope=https://www.google.com/calendar/feeds/ https://docs.google.com/feeds/

当您调用客户端库时,scope 参数会自动进行网址编码,得到以下值:
https%3a%2f%2fwww.google.com%2fcalendar%2ffeeds%2f+https%3a%2f%2fdocs.google.com%2ffeeds%2f

获取请求令牌

Java

对于 HMAC-SHA1,您需要某种方式来持久保存令牌密钥(在响应中获取),以便创建从审批页面返回的 OAuth 令牌对象。为此,请设置会话变量或 Cookie。

import com.google.gdata.client.docs.*;
import com.google.gdata.client.authn.oauth.*;

String CONSUMER_KEY = "example.com";
String CONSUMER_SECRET = "abc123doremi";

GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);
oauthParameters.setScope("https://docs.google.com/feeds/");
oauthParameters.setOAuthCallback("http://www.example.com/UpgradeToken.jsp");

GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(new OAuthHmacSha1Signer());
oauthHelper.getUnauthorizedRequestToken(oauthParameters);

使用 RSA-SHA1 时,oauth_token_secret 未使用,因此无需持久保存令牌密钥。

import com.google.gdata.client.docs.*;
import com.google.gdata.client.authn.oauth.*;

String CONSUMER_KEY = "example.com";

GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setScope("https://docs.google.com/feeds/");
oauthParameters.setOAuthCallback("http://www.example.com/UpgradeToken.jsp");

PrivateKey privKey = getPrivateKey("/path/to/your/rsakey.pk8");

GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(new OAuthRsaSha1Signer(privKey));
oauthHelper.getUnauthorizedRequestToken(oauthParameters);

...

public static PrivateKey getPrivateKey(String privKeyFileName) {
  File privKeyFile = new File(privKeyFileName);
  FileInputStream fis = new FileInputStream(privKeyFile);
  DataInputStream dis  = new DataInputStream(fis);

  byte[] privKeyBytes = new byte[(int) privKeyFile.length()];
  dis.read(privKeyBytes);
  dis.close();
  fis.close();

  String BEGIN = "-----BEGIN PRIVATE KEY-----";
  String END = "-----END PRIVATE KEY-----";
  String str = new String(privKeyBytes);
  if (str.contains(BEGIN) && str.contains(END)) {
    str = str.substring(BEGIN.length(), str.lastIndexOf(END));
  }

  KeyFactory fac = KeyFactory.getInstance("RSA");
  EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(Base64.decode(str));
  return fac.generatePrivate(privKeySpec);
}

PHP

使用 HMAC-SHA1 作为签名方法:

require_once 'Zend/Oauth/Consumer.php';

session_start();

$CONSUMER_KEY = 'example.com';
$CONSUMER_SECRET = 'abc123doremi';

// Multi-scoped token.
$SCOPES = array(
  'https://docs.google.com/feeds/',
  'https://spreadsheets.google.com/feeds/'
);

$oauthOptions = array(
  'requestScheme' => Zend_Oauth::REQUEST_SCHEME_HEADER,
  'version' => '1.0',
  'consumerKey' => $CONSUMER_KEY,
  'consumerSecret' => $CONSUMER_SECRET,
  'signatureMethod' => 'HMAC-SHA1',
  'callbackUrl' => 'http://myapp.example.com/access_token.php',
  'requestTokenUrl' => 'https://www.google.com/accounts/OAuthGetRequestToken',
  'userAuthorizationUrl' => 'https://www.google.com/accounts/OAuthAuthorizeToken',
  'accessTokenUrl' => 'https://www.google.com/accounts/OAuthGetAccessToken'
);

$consumer = new Zend_Oauth_Consumer($oauthOptions);

// When using HMAC-SHA1, you need to persist the request token in some way.
// This is because you'll need the request token's token secret when upgrading
// to an access token later on. The example below saves the token object as a session variable.
if (!isset($_SESSION['ACCESS_TOKEN'])) {
  $_SESSION['REQUEST_TOKEN'] = serialize($consumer->getRequestToken(array('scope' => implode(' ', $SCOPES))));
}

使用 RSA-SHA1 作为签名方法:

require_once 'Zend/Crypt/Rsa/Key/Private.php';
require_once 'Zend/Oauth/Consumer.php';

session_start();

$CONSUMER_KEY = 'example.com';
$SCOPE = 'https://docs.google.com/feeds/';

$oauthOptions = array(
  'requestScheme' => Zend_Oauth::REQUEST_SCHEME_HEADER,
  'version' => '1.0',
  'consumerKey' => $CONSUMER_KEY,
  'consumerSecret' => new Zend_Crypt_Rsa_Key_Private(file_get_contents(realpath('/path/to/yourRSAPrivateKey.pem'))),
  'signatureMethod' => 'RSA-SHA1',
  'callbackUrl' => 'http://myapp.example.com/access_token.php',
  'requestTokenUrl' => 'https://www.google.com/accounts/OAuthGetRequestToken',
  'userAuthorizationUrl' => 'https://www.google.com/accounts/OAuthAuthorizeToken',
  'accessTokenUrl' => 'https://www.google.com/accounts/OAuthGetAccessToken'
);

$consumer = new Zend_Oauth_Consumer($oauthOptions);

if (!isset($_SESSION['ACCESS_TOKEN'])) {
  $_SESSION['REQUEST_TOKEN'] = serialize($consumer->getRequestToken(array('scope' => $SCOPE)));
}

Python

使用 HMAC-SHA1 作为签名方法:

如果您使用的是基于 GDClient 的较新 v2.0 及更高版本类,请使用:

import gdata.gauth
import gdata.docs.client

CONSUMER_KEY = 'example.com'
CONSUMER_SECRET = 'abc123doremi'
SCOPES = ['https://docs.google.com/feeds/', 'https://www.google.com/calendar/feeds/']  # example of a multi-scoped token

client = gdata.docs.client.DocsClient(source='yourCompany-YourAppName-v1')

oauth_callback_url = 'http://%s/get_access_token' % self.request.host
request_token = client.GetOAuthToken(
    SCOPES, oauth_callback_url, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET)

# When using HMAC-SHA1, you need to persist the request_token in some way.
# You'll need the token secret when upgrading to an access token later on.
# In Google App Engine, you can use the AeSave helper:
# gdata.gauth.AeSave(request_token, 'myKey')

使用 RSA-SHA1 作为签名方法:

...

f = open('/path/to/yourRSAPrivateKey.pem')
RSA_KEY = f.read()
f.close()

request_token = client.GetOAuthToken(SCOPES, oauth_callback_url, CONSUMER_KEY, rsa_private_key=RSA_KEY)

或者,如果您使用的是基于 GDataService 的旧版 v1.0 类,则调用略有不同:

import gdata.auth
import gdata.docs.service

CONSUMER_KEY = 'example.com'
CONSUMER_SECRET = 'abc123doremi'

client = gdata.docs.service.DocsService(source='yourCompany-YourAppName-v1')
client.SetOAuthInputParameters(gdata.auth.OAuthSignatureMethod.HMAC_SHA1, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET)

req_token = client.FetchOAuthRequestToken()
client.SetOAuthToken(req_token)

使用 RSA-SHA1 作为签名方法:

...

f = open('/path/to/yourRSAPrivateKey.pem')
RSA_KEY = f.read()
f.close()

client = gdata.docs.service.DocsService(source='yourCompany-YourAppName-v1')
client.SetOAuthInputParameters(gdata.auth.OAuthSignatureMethod.RSA_SHA1, CONSUMER_KEY, rsa_key=RSA_KEY)

SCOPES = ['https://docs.google.com/feeds/', 'https://www.google.com/calendar/feeds/']  # example of a multi-scoped token
req_token = client.FetchOAuthRequestToken(scopes=SCOPES)
client.SetOAuthToken(req_token)

.NET

使用 HMAC-SHA1 作为签名方法:

using Google.GData.Client;

string CONSUMER_KEY = "example.com";
string CONSUMER_SECRET = "abc123doremi";

// Multi-scoped token.
string SCOPE = "https://www.google.com/calendar/feeds/ https://www.google.com/m8/feeds/";

OAuthParameters parameters = new OAuthParameters() {
  ConsumerKey = CONSUMER_KEY,
  ConsumerSecret = CONSUMER_SECRET,
  Scope = SCOPE,
  Callback = "http://myapp.example.com/access_token",
  SignatureMethod = "HMAC-SHA1"
}

OAuthUtil.GetUnauthorizedRequestToken(parameters);

使用 RSA-SHA1 作为签名方法:

RSA-SHA1 is not supported yet.

授权请求令牌

如需授权请求令牌,您的应用必须将用户重定向到 OAuthAuthorizeToken 网址,提示用户登录其 Google 账号。 如需详细了解 OAuthAuthorizeToken 网址,请参阅完整的适用于 Web 应用的 OAuth 身份验证

如需在应用中构建 OAuthAuthorizeToken 网址,请针对每个客户端库使用以下内容。请注意,这些示例基于之前的示例构建。

构建审批页面网址后,您的应用可以通过多种方式使用该网址将用户发送到 OAuthAuthorizeToken 处理程序。最常见的方法是将用户重定向到该网页或显示指向该网页的链接。

Java

对于 HMAC-SHA1

String approvalPageUrl = oauthHelper.createUserAuthorizationUrl(oauthParameters);
System.out.println(approvalPageUrl);

对于 RSA-SHA1

String approvalPageUrl = oauthHelper.createUserAuthorizationUrl(oauthParameters);
System.out.println(approvalPageUrl);

PHP

// If on a G Suite domain, use your domain for the hd param (e.g. 'example.com').
$approvalUrl = $consumer->getRedirectUrl(array('hd' => 'default'));
echo "<a href=\"$approvalUrl\">Grant access</a>";

或者,您也可以直接重定向到审批网址:

// If on a G Suite domain, use your domain for the hd param (e.g. 'example.com').
$consumer->redirect(array('hd' => 'default'));

Python

如果您使用的是基于 GDClient 的较新 v2.0 及更高版本类,请使用:

# req_token is from previous call to client.GetOAuthToken()
domain = None  # If on a G Suite domain, use your domain (e.g. 'example.com').
self.redirect(request_token.generate_authorization_url(google_apps_domain=domain))

如果您使用的是基于 GDataService 的旧版 v1.0 类,则流程略有不同。

# req_token is from previous call to client.FetchOAuthRequestToken()
oauth_callback_url = 'http://%s/get_access_token' % self.request.host
self.redirect(client.GenerateOAuthAuthorizationURL(callback_url=oauth_callback_url))

.NET

string authorizationUrl = OAuthUtil.CreateUserAuthorizationUrl(parameters);
Console.WriteLine(authorizationUrl);

从回调网址中提取令牌

当 Google 重定向回您的应用时,oauth_token 会作为查询参数附加到“oauth_callback_url”网址中。然后,您的应用应从其网址查询参数中提取令牌值,并重新建立 OAuth 参数。

客户端库提供了用于提取 oauth_token 的便捷方法。这些示例基于前面的示例构建。

Java

如果您选择在回调网址中保留令牌密钥(使用 HMAC-SHA1 时):

GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);

GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(new OAuthHmacSha1Signer());
oauthHelper.getOAuthParametersFromCallback(request.getQueryString(), oauthParameters);

RSA-SHA1 的唯一区别在于签名方法:

GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);

PrivateKey privKey = getPrivateKey("/path/to/your/rsakey.pk8");

GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(new OAuthRsaSha1Signer(privKey));
oauthHelper.getOAuthParametersFromCallback(request.getQueryString(), oauthParameters);

PHP

使用 PHP 库时,无需执行此步骤。

Python

如果您使用的是基于 GDClient 的较新 v2.0 及更高版本类,请使用:

# Recall request_token. In Google App Engine, use AeLoad():
# saved_request_token = gdata.gauth.AeLoad('myKey')

request_token = gdata.gauth.AuthorizeRequestToken(saved_request_token, self.request.uri)

如果您使用的是基于 GDataService 的旧版 v1.0 类,请使用:

oauth_token = gdata.auth.OAuthTokenFromUrl(self.request.uri)
if oauth_token:
  oauth_token.secret = # TODO: recall saved request_token and set the token secret here.
  oauth_token.oauth_input_params = gdata.auth.OAuthInputParams(
      gdata.auth.OAuthSignatureMethod.HMAC_SHA1, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET)
 client.SetOAuthToken(oauth_token)
else:
  print 'No oauth_token found in the URL'

RSA-SHA1 的流程类似,但没有令牌密钥:

oauth_token = gdata.auth.OAuthTokenFromUrl(self.request.uri)
if oauth_token:
  oauth_token.oauth_input_params = gdata.auth.OAuthInputParams(
      gdata.auth.OAuthSignatureMethod.RSA_SHA1, CONSUMER_KEY, rsa_key=RSA_KEY)
 client.SetOAuthToken(oauth_token)
else:
  print 'No oauth_token found in the URL'

.NET

如果您选择在回调网址中持久保留令牌密钥,请执行以下操作:

OAuthUtil.UpdateOAuthParametersFromCallback(url, parameters);

升级为访问令牌

OAuth 令牌交换的最后一步是使用 OAuthGetAccessToken 网址将授权的请求令牌升级为长期有效的访问令牌,如完整的网络应用的 OAuth 身份验证文档中所述。

以下是一些使用各个客户端库的示例:

Java

String accessToken = oauthHelper.getAccessToken(oauthParameters);
// You can also pull the OAuth token string from the oauthParameters:
// String accessToken = oauthParameters.getOAuthToken();
System.out.println("OAuth Access Token: " + accessToken);

String accessTokenSecret = oauthParameters.getOAuthTokenSecret();
System.out.println("OAuth Access Token's Secret: " + accessTokenSecret);

PHP

if (!isset($_SESSION['ACCESS_TOKEN'])) {
  if (!empty($_GET) && isset($_SESSION['REQUEST_TOKEN'])) {
    $_SESSION['ACCESS_TOKEN'] = serialize($consumer->getAccessToken($_GET, unserialize($_SESSION['REQUEST_TOKEN'])));
  }
}

Python

如果您使用的是基于 GDClient 的较新 v2.0 及更高版本类,请使用:

# Upgrade the token and save in the user's datastore
access_token = client.GetAccessToken(request_token)

# If you're using Google App Engine, you can call the AeSave() method to save
# the access token under the current logged in user's account.
#gdata.gauth.AeSave(access_token, token_key)

如果您使用的是基于 GDataService 的旧版 v1.0 类,请使用:

access_token = client.UpgradeToOAuthAccessToken()  # calls SetOAuthToken() for you

如果您在 App Engine 上使用 gdata.gauth.AeSave(),系统会将令牌和令牌密钥存储在当前登录的用户下。

.NET

OAuthUtil.GetAccessToken(parameters);

// If you want to extract the OAuth Token/TokenSecret from the OAuthParameters instance:
string accessToken = parameter.Token;
Console.WriteLine("OAuth Access Token: " + accessToken);

string accessTokenSecret = parameter.TokenSecret;
Console.WriteLine("OAuth Access Token's Secret: " + accessTokenSecret);

注意:如果您使用的是 HMAC-SHA1,请务必将访问令牌的令牌密钥与令牌值一起保存在数据库中,否则您将无法正确重建 OAuth 参数以供日后使用。

使用访问令牌

获得访问令牌后,您可以使用标准的 Google Data API 客户端库调用与服务进行互动。该库将负责对请求进行签名并为您添加正确的授权标头。通常,您会从 Cookie 或数据库中检索用户的令牌。这些示例演示了如何重建 OAuth 参数并进行客户端库调用。

Java

如果您使用的是 HMAC-SHA1,请使用:

  GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
  oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
  oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);
  oauthParameters.setOAuthToken(ACCESS_TOKEN);
  oauthParameters.setOAuthTokenSecret(TOKEN_SECRET);

  DocsService client = new DocsService("yourCompany-YourAppName-v1");
  client.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer());

  URL feedUrl = new URL("https://docs.google.com/feeds/default/private/full");
  DocumentListFeed resultFeed = client.getFeed(feedUrl, DocumentListFeed.class);
  for (DocumentListEntry entry : resultFeed.getEntries()) {
    System.out.println(entry.getTitle().getPlainText());
  }
  

RSA-SHA1 的不同之处在于,您无需设置访问令牌的密钥,并且构造签名者对象的方式也不同:

  GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
  oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
  oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);
  oauthParameters.setOAuthToken(ACCESS_TOKEN);

  PrivateKey privKey = getPrivateKey("/path/to/your/rsakey.pk8");  // See above for the defintion of getPrivateKey()

  DocsService client = new DocsService("yourCompany-YourAppName-v1");
  client.setOAuthCredentials(oauthParameters, new OAuthRsaSha1Signer(privKey));

  URL feedUrl = new URL("https://docs.google.com/feeds/default/private/full");
  DocumentListFeed resultFeed = client.getFeed(feedUrl, DocumentListFeed.class);
  for (DocumentListEntry entry : resultFeed.getEntries()) {
    System.out.println(entry.getTitle().getPlainText());
  }
  

PHP

require_once 'Zend/Gdata/Docs.php';

if (isset($_SESSION['ACCESS_TOKEN'])) {
  $accessToken = unserialize($_SESSION['ACCESS_TOKEN']);
} else {
  exit;
}


/*  Or, you could set an existing token (say one stored from your database). For HMAC-SHA1:
$accessToken = new Zend_Oauth_Token_Access();
$accessToken->setToken('1/AQfoI-qJDqkvvkf216Gc2g');
$accessToken->setTokenSecret('2c26GLW250tZiQ');
*/

$httpClient = $accessToken->getHttpClient($oauthOptions);
$client = new Zend_Gdata_Docs($httpClient, "yourCompany-YourAppName-v1");

// Retrieve user's list of Google Docs
$feed = $client->getDocumentListFeed();
foreach ($feed->entries as $entry) {
  echo "$entry->title\n";
}

Python

此代码段假定您已提取访问令牌(使用 HMAC-SHA1),并且正在调用该令牌密钥/密钥以供日后使用。

如果您使用的是基于 GDClient 的较新 v2.0 及更高版本类,请使用:

client = gdata.docs.client.DocsClient(source='yourCo-yourAppName-v1')
client.auth_token = gdata.gauth.OAuthHmacToken(CONSUMER_KEY, CONSUMER_SECRET, TOKEN,
                                               TOKEN_SECRET, gdata.gauth.ACCESS_TOKEN)
feed = client.GetDocList()
for entry in feed.entry:
  print entry.title.text

如果您使用的是基于 GDataService 的旧版 v1.0 类,请使用:

client = gdata.docs.service.DocsService(source='yourCompany-YourAppName-v1')
client.SetOAuthInputParameters(SIG_METHOD, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET)

# the token key and secret should be recalled from your database
client.SetOAuthToken(gdata.auth.OAuthToken(key=TOKEN, secret=TOKEN_SECRET))

feed = client.GetDocumentListFeed()
for entry in feed.entry:
  print entry.title.text

.NET

如果您使用的是 HMAC-SHA1,请使用:

OAuthParameters parameters = new OAuthParameters() {
  ConsumerKey = CONSUMER_KEY,
  ConsumerSecret = CONSUMER_SECRET,
  Token = ACCESS_TOKEN,
  TokenSecret = TOKEN_SECRET
}

GOAuthRequestFactory requestFactory = new GOAuthRequestFactory("writely", APPLICATION_NAME, parameters);

DocsService service = new DocsService(APPLICATION_NAME);
service.RequestFactory = requestFactory;

DocumentsListQuery query = new DocumentsListQuery();
DocumentsFeed feed = service.Query(query);
foreach (DocumentEntry entry in feed.Entries) {
  Console.WriteLine(entry.Title.Text);
}

RSA-SHA1 的不同之处在于,您无需设置访问令牌的密钥,并且构造签名者对象的方式也不同:

RSA-SHA1 is not supported yet.

其他三方模式 OAuth 资源和示例

返回页首

双方模式 OAuth

双步 OAuth 允许受信任的应用在用户未直接参与的情况下访问用户的 Google 数据。以下两个主要群体可以使用两方模式的 OAuth:

G Suite 网域管理员:管理员可以通过 Google Data API 构建脚本和自定义应用,以管理其网域的用户数据。如需了解如何管理与您的 G Suite 网域相关联的密钥和 secret,以及如何授予全局访问权限控制权,请参阅“管理 OAuth 密钥和 secret”

第三方软件供应商:供应商可能会提供使用双腿 OAuth 与 G Suite 集成的应用。您可以在“管理 API 客户端”页面上授予第三方应用的访问权限,也可以通过从 G Suite 应用商店安装应用来授予访问权限。

根据正常的授权流程(也称为三方模式 OAuth),不需要访问令牌。

以下客户端库示例演示了如何设置客户端以使用 HMAC-SHA1 实现双向 OAuth。

Java

import com.google.gdata.client.docs.*;
import com.google.gdata.client.authn.oauth.*;

String CONSUMER_KEY = "example.com";
String CONSUMER_SECRET = "abc123doremi";

GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);

DocsService client = new DocsService("yourCompany-YourAppName-v1");
client.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer());

// Retrieve user's list of Google Docs
String user = "any.user@anydomain.com";
URL feedUrl = new URL("https://docs.google.com/feeds/default/private/full" +
                      "?xoauth_requestor_id=" + user);

DocumentListFeed resultFeed = client.getFeed(feedUrl, DocumentListFeed.class);
for (DocumentListEntry entry : resultFeed.getEntries()) {
  System.out.println(entry.getTitle().getPlainText());
}

PHP

require_once 'Zend/Oauth/Consumer.php';
require_once 'Zend/Gdata/Docs.php';

$CONSUMER_KEY = 'example.com';
$CONSUMER_SECRET = 'abc123doremi';
$USER = 'any.user@anydomain.com';

$oauthOptions = array(
    'requestScheme' => Zend_Oauth::REQUEST_SCHEME_HEADER,
    'version' => '1.0',
    'signatureMethod' => 'HMAC-SHA1',
    'consumerKey' => $CONSUMER_KEY,
    'consumerSecret' => $CONSUMER_SECRET
);

$consumer = new Zend_Oauth_Consumer($oauthOptions);
$token = new Zend_Oauth_Token_Access();
$httpClient = $token->getHttpClient($oauthOptions);

$client = new Zend_Gdata_Docs($httpClient);

// Retrieve user's list of Google Docs
$feed = $client->getDocumentListFeed('https://docs.google.com/feeds/default/private/full?xoauth_requestor_id=' . urlencode($USER));
foreach ($feed->entries as $entry) {
  echo "$entry->title\n";
}

Python

如果您使用的是基于 GDClient 的较新 v2.0 及更高版本类,请使用:

import gdata.gauth
import gdata.docs.client

CONSUMER_KEY = 'example.com'
CONSUMER_SECRET = 'abc123doremi'
requestor_id = 'any.user@anydomain.com'

client = gdata.docs.client.DocsClient(source='yourCompany-YourAppName-v1')
client.auth_token = gdata.gauth.TwoLeggedOAuthHmacToken(
    CONSUMER_KEY, CONSUMER_SECRET, requestor_id)

# Retrieve user's list of Google Docs
feed = client.GetDocList()
for entry in feed.entry:
  print entry.title.text

如果您使用的是基于 GDataService 的旧版 v1.0 类,请使用:

import gdata.auth
import gdata.docs.service

CONSUMER_KEY = 'example.com'
CONSUMER_SECRET = 'abc123doremi'
SIG_METHOD = gdata.auth.OAuthSignatureMethod.HMAC_SHA1

requestor_id = 'any.user@anydomain.com'

client = gdata.docs.service.DocsService(source='yourCompany-YourAppName-v1')
client.SetOAuthInputParameters(SIG_METHOD, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET,
                               two_legged_oauth=True, requestor_id=requestor_id)

# Retrieve user's list of Google Docs
feed = client.GetDocumentListFeed()
for entry in feed.entry:
  print entry.title.text

# Change to another user on your domain
client.GetOAuthInputParameters().requestor_id = 'another.user@example.com'

.NET

using Google.GData.Client;
using Google.GData.Documents;

// Create an OAuth factory to use
GOAuthRequestFactory requestFactory = new GOAuthRequestFactory("writely", "yourCompany-YourAppName-v1");
requestFactory.ConsumerKey = "example.com";
requestFactory.ConsumerSecret = "abc123doremi";

String user = "any.user@anydomain.com";

DocumentsService client = new DocumentsService("yourCompany-YourAppName-v1");
client.RequestFactory = requestFactory;

// Retrieve user's list of Google Docs
DocumentsListQuery query = new DocumentsListQuery();
query.Uri = new OAuthUri("https://docs.google.com/feeds/default/private/full", user, requestFactory.ConsumerKey);

DocumentsFeed feed = client.Query(query);

foreach (DocumentEntry entry in feed.Entries)
{
  Console.WriteLine(entry.Title.Text);
}

其他双方模式 OAuth 资源和示例

生成自签名私钥和公共证书

私钥用于生成签名,该签名必须包含在每个请求中。Google 会使用嵌入在证书中的公钥来验证签名。公钥必须是采用 PEM 格式的 X.509 证书中编码的 1024 位 RSA 密钥。证书应在注册时发送给 Google。

以下部分提供了有关如何使用两种特定工具(即 OpenSSL 实用程序和 Java 的 keytool 实用程序)生成密钥和证书的示例。

这些示例并非专门针对 Google Data API;您可以将相同的实用程序用于生成任何用途的密钥。

以下示例假设贵公司的名称为 My_Company,位于美国加利福尼亚州山景城,域名为 example.com。

使用 OpenSSL 生成密钥

如需创建一对 RSA 密钥和相应的证书,您可以使用以下命令:

# Generate the RSA keys and certificate
openssl req -x509 -nodes -days 365 -newkey rsa:1024 -sha1 -subj \
  '/C=US/ST=CA/L=Mountain View/CN=www.example.com' -keyout \
  myrsakey.pem -out /tmp/myrsacert.pem

警告:包含 -nodes 参数会创建没有密码保护的私钥。不过,为了提高安全性,您应考虑省略此参数。

-sha1 参数指定密钥将用于生成 SHA1 签名。

-subj 参数用于指定证书所代表的应用的身份。

-keyout 参数用于指定将包含密钥的文件。此文件包含敏感信息,应受到保护,不得与任何人共享。

-out 参数用于指定将包含 PEM 格式证书的文件(可在注册时发送给 Google)。

为 .NET 客户端生成密钥

.NET 框架无法识别以 PEM 格式存储的密钥或证书。因此,创建 .pem 文件后,还需要执行一个额外的步骤:

openssl pkcs12 -export -in test_cert.pem -inkey myrsacert.pem -out myrsacert.pfx -name "Testing Certificate"

此步骤会根据您的私钥和证书生成 PFX 文件。此文件可以导入到 .NET 客户端库中,用于对向 Google Data API 发出的请求进行数字签名。

为 Java 客户端生成密钥

Java 客户端接受 PKCS#8 格式的私钥。按照上述说明生成密钥/证书后,根据生成的 .pem 文件创建 .pk8 文件:

openssl pkcs8 -in myrsakey.pem -topk8 -nocrypt -out myrsakey.pk8

或者,您也可以使用 Java 密钥库和 keytool 实用程序创建 RSA 密钥对和相应的证书。使用以下命令:

# Generate the RSA keys and certificate
keytool -genkey -v -alias Example -keystore ./Example.jks\
  -keyalg RSA -sigalg SHA1withRSA\
  -dname "CN=www.example.com, OU=Engineering, O=My_Company, L=Mountain  View, ST=CA, C=US"\
  -storepass changeme -keypass changeme

警告:“changeme”不是一个好的密码,这只是一个示例。

-dname 参数用于指定证书所代表的应用的身份。-storepass 参数用于指定保护密钥库的密码。-keypass 参数用于指定保护私钥的密码。

如需将证书写入可在 ManageDomains 工具中使用的文件,请使用以下命令:

# Output the public certificate to a file
keytool -export -rfc -keystore ./Example.jks -storepass changeme \
  -alias Example -file mycert.pem

返回页首