Google 数据协议客户端库中的 OAuth

警告:本页面介绍的是 Google 的旧版 API,即 Google 数据 API;它仅与 Google 数据 API 目录中列出的许多 API 相关,其中许多 API 已替换为较新的 API。如需了解特定新 API,请参阅新 API 的文档。如需了解如何使用较新的 API 向请求授权,请参阅 Google 帐号身份验证和授权

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

OAuth 接口允许基于网络的应用代表用户访问 Google 服务。为保持高级别的安全,OAuth 允许应用获取访问令牌,而无需处理用户的帐号登录信息。

Google Data API 客户端库提供了各种方法,可帮助您在 Web 应用中使用 OAuth。具体而言,您可以通过多种方法来构造请求令牌、为请求令牌授权以及用已获授权的请求令牌换取访问令牌。在向 Google 数据服务发出请求时,这些库还会处理必要的签名算法。

观众

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

本文档假设您熟悉 OAuth 接口以及将 OAuth 整合到 Web 应用的一般流程。如需查看 OAuth 协议的完整说明,请参阅适用于 Web 应用的 OAuth 身份验证或访问 oauth.net 以查看官方规范。

使用不含客户端库的三方模式 OAuth 和 Google 数据 API

如果您希望 Web 应用使用 OAuth 作为授权方法与 Google 数据服务进行交互,则需要知道适用于 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. 注册域名

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

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 数据 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

如果您已选择将令牌 Secret 保留在回调网址中(使用 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 网址将已获授权的请求令牌升级为长期访问令牌,如完整的适用于 Web 应用的 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 的区别在于,您无需设置访问令牌的 Secret,并且构建签名者对象也有所不同:

  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 的区别在于,您无需设置访问令牌的 Secret,并且构建签名者对象也有所不同:

RSA-SHA1 is not supported yet.

附加的三方模式 OAuth 资源和示例

返回页首

两方模式的 OAuth

两方模式 OAuth 允许受信任的应用在不直接参与的情况下访问用户的 Google 数据。两个密钥组可以使用两方模式的 OAuth:

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

第三方软件供应商:供应商可能会提供使用两方模式 OAuth 与 G Suite 集成的应用。您可以通过“管理 API”客户端页面或通过 G Suite Marketplace 安装来为第三方应用授予访问权限。

按照常规授权流程(也称为三方模式 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 数据 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 数据 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

返回页首