Google Data Protocol 用戶端程式庫中的 OAuth

警告:本頁面說明 Google 的舊版 API (即 Google Data API);該 API 只與 Google Data API 目錄中列出的 API 相關,其中許多 API 已由新版 API 取代。如需特定新的 API 的相關資訊,請參閱新 API 的說明文件。如要瞭解如何使用新版 API 授權要求,請參閱 Google 帳戶驗證與授權

本文說明如何使用 Google Data API 用戶端程式庫來連結 Google 的網路應用程式 OAuth 驗證

OAuth 介面可讓網頁式應用程式代表使用者存取 Google 服務。為維持高安全性,OAuth 可讓應用程式取得存取權杖,而無需處理使用者的帳戶登入資訊。

Google Data API 用戶端程式庫提供方法,可協助您在網路應用程式中使用 OAuth。具體來說,有一種方法可以建構要求憑證、授權要求憑證,以及交換存取憑證的授權要求憑證。程式庫在向 Google Data 服務發出要求時,也會處理必要的簽署演算法。

目標對象

本文件的適用對象,是想讓網頁式應用程式的使用者透過 Google Data API 用戶端程式庫,以使用者的名義存取 Google 服務。

本文假設您已熟悉 OAuth 介面,以及將 OAuth 整合至網路應用程式的一般程序。如需 OAuth 通訊協定的完整說明,請參閱網路應用程式的 OAuth 驗證oauth.net 的官方規格說明。

在沒有用戶端程式庫的情況下使用三足式 OAuth 和 Google Data API

如果您希望網路應用程式使用 OAuth 做為授權方法與 Google Data 服務互動,只需瞭解網路應用程式的 OAuth 驗證即可。如果不想使用 Google Data API 用戶端程式庫,則不需要這麼做。

以下概述您的應用程式可能如何使用 OAuth 驗證使用者:

  1. 您的應用程式提出已簽署的要求,會從 OAuthRequestToken 端點擷取初始 OAuth 要求憑證。
  2. 您的應用程式會將使用者重新導向適當的 OAuthAuthorizeToken 網址,以授權要求憑證。
  3. 授予存取權後,系統會將使用者重新導向回您的應用程式 (oauth_callback 網址)
  4. 您的應用程式會使用 OAuthGetAccessToken 端點傳送已簽署的要求,將授權要求憑證升級為存取權杖。

Google Data API 用戶端程式庫會為您處理各種詳細資訊,藉此簡化這項授權程序。本文將說明如何進行。

註冊網頁應用程式

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 值設為允許存取的最窄網址。這麼做可降低意外取得及外洩個人資料的風險。舉例來說,如果您想存取目前使用者的非公開文件清單資訊提供,請使用 https://docs.google.com/feeds/default/private/full 這個範圍,而不是使用可提供所有「文件清單」資訊提供存取權的整個範圍,例如 https://docs.google.com/feeds/

多範圍憑證

如要建立可存取多個 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 網址,請參閱完整的網路應用程式 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 用戶端程式庫呼叫來與服務互動。程式庫會負責簽署要求,並為您填入正確的「Authorization」標頭。一般而言,您會透過 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 網域相關聯的金鑰和密鑰,以及如何授予全域存取權控管機制,請參閱管理 OAuth 金鑰和密鑰

第三方軟體供應商:供應商可能會提供使用雙足式 OAuth 與 G Suite 整合的應用程式。您可以透過 Management 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 會使用憑證中嵌入的公開金鑰來驗證簽名。公開金鑰必須是 1024 位元 RSA 金鑰,並以 PEM 格式的 X.509 憑證編碼。應於註冊時將憑證傳送給 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 Key Store 和 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 參數會指定保護 KeyStore 的密碼。-keypass 參數會指定保護私密金鑰的密碼。

如要將憑證寫入可在 ManageDomains 工具中使用的檔案,請使用下列指令:

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

返回頁首