實作伺服器端授權

向 Gmail API 發出的要求必須使用 OAuth 2.0 授權 憑證應用程式時,您應該使用伺服器端流程 需要代表使用者存取 Google API 這種方法需要傳送一次性授權碼, 用戶端傳送至伺服器此代碼用於取得存取權杖 更新權杖

如要進一步瞭解伺服器端 Google OAuth 2.0 實作,請參閱 針對網路伺服器應用程式使用 OAuth 2.0

目錄

建立用戶端 ID 和用戶端密鑰

如要開始使用 Gmail API,您必須 使用 設定工具,會引導您在 Google API 控制台,啟用 API 並建立憑證。

  1. 在「憑證」頁面上,按一下「建立憑證」>OAuth 用戶端 建立 OAuth 2.0 憑證,或依序選取 [建立憑證] > [建立憑證]。服務 帳戶金鑰,以建立服務帳戶。
  2. 如果您已建立 OAuth 用戶端 ID,請選取應用程式類型。
  3. 填寫表單,然後按一下「建立」

系統已列出應用程式的用戶端 ID 和服務帳戶金鑰 「憑證」頁面。詳情請按一下用戶端 ID;參數會有所不同 視 ID 類型而定,但可能包含電子郵件地址、用戶端密鑰 JavaScript 來源或重新導向 URI

記下用戶端 ID,稍後您必須在程式碼中加入這組 ID。

處理授權要求

使用者首次載入應用程式時,會看到 對話方塊,用於授權您的應用程式存取其 Gmail 帳戶,該帳戶須具備所要求的權限範圍。在此初始之後 只有在您的 應用程式用戶端 ID 變更,或要求的範圍已變更。

驗證使用者

此初始登入會傳回授權結果物件,其中包含 授權碼

交換存取權杖的授權碼

授權碼是由您的伺服器交換而來的一次性代碼 存取權杖。這個存取權杖會傳遞至 Gmail API,以便授予 您的應用程式可在限定時間內存取使用者資料。

如果您的應用程式需要「offline」存取權,首次交換應用程式時 授權代碼,也會收到用於存取驗證代碼的更新權杖 並在前一個權杖過期後接收新的存取權杖。您的應用程式 儲存這個更新權杖 (通常是儲存在伺服器的資料庫中), 以便稍後使用

下列程式碼範例示範如何交換 具有 offline 存取權及儲存更新權杖的存取權杖。

Python

CLIENTSECRETS_LOCATION 值換成 client_secrets.json 檔案。

import logging
from oauth2client.client import flow_from_clientsecrets
from oauth2client.client import FlowExchangeError
from apiclient.discovery import build
# ...


# Path to client_secrets.json which should contain a JSON document such as:
#   {
#     "web": {
#       "client_id": "[[YOUR_CLIENT_ID]]",
#       "client_secret": "[[YOUR_CLIENT_SECRET]]",
#       "redirect_uris": [],
#       "auth_uri": "https://accounts.google.com/o/oauth2/auth",
#       "token_uri": "https://accounts.google.com/o/oauth2/token"
#     }
#   }
CLIENTSECRETS_LOCATION = '<PATH/TO/CLIENT_SECRETS.JSON>'
REDIRECT_URI = '<YOUR_REGISTERED_REDIRECT_URI>'
SCOPES = [
    'https://www.googleapis.com/auth/gmail.readonly',
    'https://www.googleapis.com/auth/userinfo.email',
    'https://www.googleapis.com/auth/userinfo.profile',
    # Add other requested scopes.
]

class GetCredentialsException(Exception):
  """Error raised when an error occurred while retrieving credentials.

  Attributes:
    authorization_url: Authorization URL to redirect the user to in order to
                       request offline access.
  """

  def __init__(self, authorization_url):
    """Construct a GetCredentialsException."""
    self.authorization_url = authorization_url


class CodeExchangeException(GetCredentialsException):
  """Error raised when a code exchange has failed."""


class NoRefreshTokenException(GetCredentialsException):
  """Error raised when no refresh token has been found."""


class NoUserIdException(Exception):
  """Error raised when no user ID could be retrieved."""


def get_stored_credentials(user_id):
  """Retrieved stored credentials for the provided user ID.

  Args:
    user_id: User's ID.
  Returns:
    Stored oauth2client.client.OAuth2Credentials if found, None otherwise.
  Raises:
    NotImplemented: This function has not been implemented.
  """
  # TODO: Implement this function to work with your database.
  #       To instantiate an OAuth2Credentials instance from a Json
  #       representation, use the oauth2client.client.Credentials.new_from_json
  #       class method.
  raise NotImplementedError()


def store_credentials(user_id, credentials):
  """Store OAuth 2.0 credentials in the application's database.

  This function stores the provided OAuth 2.0 credentials using the user ID as
  key.

  Args:
    user_id: User's ID.
    credentials: OAuth 2.0 credentials to store.
  Raises:
    NotImplemented: This function has not been implemented.
  """
  # TODO: Implement this function to work with your database.
  #       To retrieve a Json representation of the credentials instance, call the
  #       credentials.to_json() method.
  raise NotImplementedError()


def exchange_code(authorization_code):
  """Exchange an authorization code for OAuth 2.0 credentials.

  Args:
    authorization_code: Authorization code to exchange for OAuth 2.0
                        credentials.
  Returns:
    oauth2client.client.OAuth2Credentials instance.
  Raises:
    CodeExchangeException: an error occurred.
  """
  flow = flow_from_clientsecrets(CLIENTSECRETS_LOCATION, ' '.join(SCOPES))
  flow.redirect_uri = REDIRECT_URI
  try:
    credentials = flow.step2_exchange(authorization_code)
    return credentials
  except FlowExchangeError, error:
    logging.error('An error occurred: %s', error)
    raise CodeExchangeException(None)


def get_user_info(credentials):
  """Send a request to the UserInfo API to retrieve the user's information.

  Args:
    credentials: oauth2client.client.OAuth2Credentials instance to authorize the
                 request.
  Returns:
    User information as a dict.
  """
  user_info_service = build(
      serviceName='oauth2', version='v2',
      http=credentials.authorize(httplib2.Http()))
  user_info = None
  try:
    user_info = user_info_service.userinfo().get().execute()
  except errors.HttpError, e:
    logging.error('An error occurred: %s', e)
  if user_info and user_info.get('id'):
    return user_info
  else:
    raise NoUserIdException()


def get_authorization_url(email_address, state):
  """Retrieve the authorization URL.

  Args:
    email_address: User's e-mail address.
    state: State for the authorization URL.
  Returns:
    Authorization URL to redirect the user to.
  """
  flow = flow_from_clientsecrets(CLIENTSECRETS_LOCATION, ' '.join(SCOPES))
  flow.params['access_type'] = 'offline'
  flow.params['approval_prompt'] = 'force'
  flow.params['user_id'] = email_address
  flow.params['state'] = state
  return flow.step1_get_authorize_url(REDIRECT_URI)


def get_credentials(authorization_code, state):
  """Retrieve credentials using the provided authorization code.

  This function exchanges the authorization code for an access token and queries
  the UserInfo API to retrieve the user's e-mail address.
  If a refresh token has been retrieved along with an access token, it is stored
  in the application database using the user's e-mail address as key.
  If no refresh token has been retrieved, the function checks in the application
  database for one and returns it if found or raises a NoRefreshTokenException
  with the authorization URL to redirect the user to.

  Args:
    authorization_code: Authorization code to use to retrieve an access token.
    state: State to set to the authorization URL in case of error.
  Returns:
    oauth2client.client.OAuth2Credentials instance containing an access and
    refresh token.
  Raises:
    CodeExchangeError: Could not exchange the authorization code.
    NoRefreshTokenException: No refresh token could be retrieved from the
                             available sources.
  """
  email_address = ''
  try:
    credentials = exchange_code(authorization_code)
    user_info = get_user_info(credentials)
    email_address = user_info.get('email')
    user_id = user_info.get('id')
    if credentials.refresh_token is not None:
      store_credentials(user_id, credentials)
      return credentials
    else:
      credentials = get_stored_credentials(user_id)
      if credentials and credentials.refresh_token is not None:
        return credentials
  except CodeExchangeException, error:
    logging.error('An error occurred during code exchange.')
    # Drive apps should try to retrieve the user and credentials for the current
    # session.
    # If none is available, redirect the user to the authorization URL.
    error.authorization_url = get_authorization_url(email_address, state)
    raise error
  except NoUserIdException:
    logging.error('No user ID could be retrieved.')
  # No refresh token has been retrieved.
  authorization_url = get_authorization_url(email_address, state)
  raise NoRefreshTokenException(authorization_url)

使用儲存的憑證授權

使用者在首次成功授權後造訪您的應用程式 流程,應用程式可使用儲存的重新整理權杖,將要求授權給要求。 而不會再次提示使用者

如果您已驗證使用者身分,應用程式 更新權杖,並將權杖儲存在伺服器端 會很有幫助如果更新權杖遭到撤銷或無效, 必須能夠攔截這些內容並採取適當行動。

使用 OAuth 2.0 憑證

擷取 OAuth 2.0 憑證後,如 可用於授權 Gmail 服務物件 並傳送要求至 API

建立服務物件的例項

這個程式碼範例說明如何將服務物件例項化,然後加以授權 並對其發出 API 要求

Python

from apiclient.discovery import build
# ...

def build_service(credentials):
  """Build a Gmail service object.

  Args:
    credentials: OAuth 2.0 credentials.

  Returns:
    Gmail service object.
  """
  http = httplib2.Http()
  http = credentials.authorize(http)
  return build('gmail', 'v1', http=http)

傳送授權要求,並檢查憑證是否遭到撤銷

下列程式碼片段會使用已授權的 Gmail 服務執行個體, 擷取訊息清單

如果發生錯誤,程式碼會檢查 HTTP 401 狀態碼。 處理時,應將使用者重新導向至授權網頁 網址。

如需更多 Gmail API 作業,請參閱 API 參考資料

Python

from apiclient import errors
# ...

def ListMessages(service, user, query=''):
  """Gets a list of messages.

  Args:
    service: Authorized Gmail API service instance.
    user: The email address of the account.
    query: String used to filter messages returned.
           Eg.- 'label:UNREAD' for unread Messages only.

  Returns:
    List of messages that match the criteria of the query. Note that the
    returned list contains Message IDs, you must use get with the
    appropriate id to get the details of a Message.
  """
  try:
    response = service.users().messages().list(userId=user, q=query).execute()
    messages = response['messages']

    while 'nextPageToken' in response:
      page_token = response['nextPageToken']
      response = service.users().messages().list(userId=user, q=query,
                                         pageToken=page_token).execute()
      messages.extend(response['messages'])

    return messages
  except errors.HttpError, error:
    print 'An error occurred: %s' % error
    if error.resp.status == 401:
      # Credentials have been revoked.
      # TODO: Redirect the user to the authorization URL.
      raise NotImplementedError()

後續步驟

確定要授權 Gmail API 要求後, 按照 開發人員指南章節。

如要進一步瞭解可用的 API 方法,請參閱 API 參考資料