تنفيذ التفويض من جانب الخادم

يجب تفويض الطلبات المُرسَلة إلى واجهة برمجة التطبيقات Gmail API باستخدام بيانات اعتماد OAuth 2.0. يجب استخدام عملية المعالجة من جهة الخادم عندما يحتاج تطبيقك إلى الوصول إلى Google APIs نيابةً عن المستخدم، على سبيل المثال عندما يكون المستخدم غير متصل بالإنترنت. تتطلّب هذه الطريقة إرسال رمز تفويض صالح لمرة واحدة من العميل إلى الخادم، ويُستخدَم هذا الرمز للحصول على رمز مميّز للوصول ورموزاً مميّزة لإعادة التحميل لخادمك.

لمزيد من المعلومات عن تنفيذ Google OAuth 2.0 من جهة الخادم، يُرجى الاطّلاع على مقالة استخدام OAuth 2.0 لتطبيقات خادم الويب.

المحتويات

إنشاء معرّف عميل وسر عميل

لبدء استخدام Gmail API، عليك أولاً استخدام أداة الإعداد التي تقدّم لك إرشادات خلال عملية إنشاء المشروع في "وحدة تحكّم واجهة برمجة تطبيقات Google" وتفعيل واجهة برمجة التطبيقات وإنشاء بيانات الاعتماد.

  1. من صفحة "بيانات الاعتماد"، انقر على إنشاء بيانات اعتماد > معرِّف عميل OAuth لإنشاء بيانات اعتماد OAuth 2.0 أو إنشاء بيانات اعتماد > مفتاح حساب الخدمة لإنشاء حساب خدمة.
  2. إذا أنشأت معرِّف عميل OAuth، اختَر نوع تطبيقك.
  3. املأ النموذج وانقر على إنشاء.

تم إدراج معرّفات عملاء تطبيقك ومفاتيح حسابات الخدمة في صفحة "بيانات الاعتماد". للاطّلاع على التفاصيل، انقر على معرّف عميل. تختلف المَعلمات تبعًا لنوع المعرّف، ولكن قد تتضمّن عنوان البريد الإلكتروني أو مفتاح سر العميل أو مصادر JavaScript أو معرّفات الموارد المنتظمة لإعادة التوجيه.

سجِّل معرّف العميل لأنّك ستحتاج إلى إضافته إلى الرمز لاحقًا.

معالجة طلبات التفويض

عندما يحمِّل المستخدم تطبيقك لأول مرة، يظهر له مربع حوار لمنح إذن لتطبيقك بالوصول إلى حسابه على Gmail باستخدام نطاقات الأذونات المطلوبة. بعد هذا المنح الأولي للسماح، لا يظهر مربّع حوار الأذونات للمستخدم إلا إذا تغيّر رقم تعريف العميل لتطبيقك أو تغيّرت النطاقات المطلوبة.

مصادقة المستخدم

تؤدي عملية تسجيل الدخول الأولية هذه إلى عرض عنصر نتيجة تفويض يحتوي على رمز تفويض في حال نجاح العملية.

تبديل رمز التفويض برمز مميّز للوصول

رمز التفويض هو رمز صالح لمرة واحدة يمكن لخادمك استبداله برمز مميّز للوصول. يتم تمرير رمز الوصول هذا إلى واجهة برمجة التطبيقات 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 وإرسال طلبات إلى واجهة برمجة التطبيقات.

إنشاء مثيل لعنصر خدمة

يوضِّح نموذج الرمز البرمجي هذا كيفية إنشاء مثيل لعنصر الخدمة ثم تفويضه للقيام بطلبات واجهة برمجة التطبيقات.

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 ل retrieving a list of messages.

في حال حدوث خطأ، يبحث الرمز عن رمز حالة HTTP‏ 401، والذي يجب التعامل معه من خلال إعادة توجيه المستخدم إلى عنوان URL للتفويض.

تم توثيق المزيد من عمليات Gmail 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، يمكنك بدء التعامل مع الرسائل والمحادثات والعلامات، كما هو موضّح في أقسام أدلة المطوّرين.

يمكنك الاطّلاع على مزيد من المعلومات عن طرق واجهة برمجة التطبيقات المتاحة في مرجع واجهة برمجة التطبيقات.