استخدام OAuth 2.0 لتطبيقات خادم الويب

يوضح هذا المستند كيفية استخدام تطبيقات خادم الويب لمكتبات برامج Google API أو نقاط نهاية Google OAuth 2.0 لتنفيذ تفويض OAuth 2.0 للوصول إلى Google APIs.

يسمح OAuth 2.0 للمستخدمين بمشاركة بيانات محدّدة مع أحد التطبيقات مع الحفاظ على خصوصية أسماء المستخدمين وكلمات المرور والمعلومات الأخرى. على سبيل المثال، يمكن لأحد التطبيقات استخدام OAuth 2.0 للحصول على إذن من المستخدمين لتخزين الملفات في Google Drive.

مسار OAuth 2.0 هذا مخصص لتفويض المستخدم تحديدًا. وقد تم تصميم هذا البرنامج للتطبيقات التي يمكنها تخزين معلومات سرية والحفاظ على حالتها. ويمكن لتطبيق خادم الويب المعتمَد بشكل صحيح الوصول إلى واجهة برمجة التطبيقات أثناء تفاعل المستخدم مع التطبيق أو بعد مغادرة المستخدم للتطبيق.

تستخدم تطبيقات خادم الويب أيضًا بشكل متكرر حسابات الخدمة للسماح بطلبات البيانات من واجهة برمجة التطبيقات، لا سيّما عند طلب واجهات Cloud APIs للوصول إلى البيانات المستندة إلى المشاريع بدلاً من البيانات الخاصة بالمستخدم. يمكن لتطبيقات خادم الويب استخدام حسابات الخدمة مع تفويض المستخدم.

مكتبات العملاء

تستخدم الأمثلة الخاصة باللغات والمعروضة في هذه الصفحة مكتبات برامج Google API لتنفيذ بروتوكول OAuth 2.0. لتشغيل نماذج الرموز، يجب أولاً تثبيت مكتبة البرامج بلغتك.

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

تتوفر مكتبات عملاء Google API للتطبيقات من جهة الخادم باللغات التالية:

المتطلبات الأساسية

تفعيل واجهات برمجة التطبيقات لمشروعك

ويجب تفعيل واجهات برمجة التطبيقات هذه في API Consoleلأي تطبيق يستدعي Google APIs.

لتفعيل واجهة برمجة تطبيقات لمشروعك:

  1. Open the API Library في Google API Console.
  2. If prompted, select a project, or create a new one.
  3. تسرد علامة التبويب " API Library " جميع واجهات برمجة التطبيقات المتاحة، مجمّعة حسب مجموعة المنتجات ومدى رواجها. إذا كانت واجهة برمجة التطبيقات التي تريد تفعيلها غير مرئية في القائمة، استخدِم ميزة البحث للعثور عليها، أو انقر على عرض الكل في مجموعة المنتجات التي تنتمي إليها.
  4. اختَر واجهة برمجة التطبيقات التي تريد تفعيلها، ثم انقر على الزر تفعيل.
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

إنشاء بيانات اعتماد التفويض

يجب أن تتوفر لدى أي تطبيق يستخدم OAuth 2.0 للوصول إلى Google APIs بيانات اعتماد تفويض لتعريف التطبيق على خادم OAuth 2.0 من Google. توضّح الخطوات التالية كيفية إنشاء بيانات اعتماد لمشروعك. ويمكن لتطبيقاتك بعد ذلك استخدام بيانات الاعتماد للوصول إلى واجهات برمجة التطبيقات التي فعّلتها لهذا المشروع.

  1. Go to the Credentials page.
  2. انقر على إنشاء بيانات اعتماد > معرِّف عميل OAuth.
  3. اختَر نوع تطبيق تطبيق الويب.
  4. املأ النموذج وانقر على إنشاء. في التطبيقات التي تستخدم لغات وأُطر عمل، مثل PHP وJava وPython وRuby و .NET يجب تحديد معرّفات موارد منتظمة (URI) لإعادة التوجيه. معرّفات الموارد المنتظمة (URI) لإعادة التوجيه هي نقاط النهاية التي يمكن لخادم OAuth 2.0 إرسال الردود إليها. ويجب أن تتقيّد نقاط النهاية هذه بقواعد التحقّق من الصحة من Google.

    لأغراض الاختبار، يمكنك تحديد معرّفات الموارد المنتظمة (URI) التي تشير إلى الجهاز المحلي، مثل http://localhost:8080. مع أخذ ذلك في الاعتبار، يُرجى ملاحظة أنّ جميع الأمثلة في هذا المستند تستخدم http://localhost:8080 باعتباره معرّف الموارد المنتظم (URI) لإعادة التوجيه.

    ننصحك بتصميم نقاط نهاية المصادقة في تطبيقك كي لا يعرض تطبيقك رموز التفويض لموارد أخرى في الصفحة.

بعد إنشاء بيانات الاعتماد، نزِّل ملف client_secret.json من API Console. يمكنك تخزين الملف بأمان في مكان لا يمكن سوى لتطبيقك الوصول إليه.

تحديد نطاقات الوصول

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

قبل البدء في تنفيذ تفويض OAuth 2.0، ننصحك بتحديد النطاقات التي سيحتاج تطبيقك إلى إذن للوصول إليها.

ننصح أيضًا بأن يطلب تطبيقك الوصول إلى نطاقات التفويض من خلال عملية تفويض تزايدي، والتي يطلب فيها التطبيق الوصول إلى بيانات المستخدمين في السياق. وتساعد أفضل الممارسات هذه المستخدمين على فهم سبب احتياج التطبيق إلى إذن الوصول الذي يطلبه بسهولة أكبر.

يحتوي مستند نطاقات OAuth 2.0 API على قائمة كاملة بالنطاقات التي قد تستخدمها للوصول إلى واجهات Google APIs.

المتطلبات المتعلقة باللغات

لتشغيل أي من عيّنات التعليمات البرمجية في هذا المستند، ستحتاج إلى حساب على Google واتصال بالإنترنت ومتصفّح ويب. إذا كنت تستخدم إحدى مكتبات برامج واجهة برمجة التطبيقات، يمكنك الاطّلاع أيضًا على المتطلبات الخاصة باللغة أدناه.

PHP

لتشغيل نماذج التعليمات البرمجية PHP في هذا المستند، ستحتاج إلى:

  • لغة PHP 5.6 أو إصدار أحدث مع تثبيت واجهة سطر الأوامر (CLI) وإضافة JSON.
  • أداة إدارة التبعية Composer
  • مكتبة برامج Google APIs للغة PHP:

    composer require google/apiclient:^2.10

Python

لتشغيل عيّنات التعليمات البرمجية للغة بايثون في هذا المستند، ستحتاج إلى:

  • Python 2.6 أو أحدث
  • هي أداة إدارة الحزمة pip.
  • مكتبة برامج Google APIs للغة Python:
    pip install --upgrade google-api-python-client
  • تمثّل هذه السمة google-auth وgoogle-auth-oauthlib وgoogle-auth-httplib2 لتفويض المستخدم.
    pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
  • إطار عمل تطبيق الويب Flask Python
    pip install --upgrade flask
  • مكتبة HTTP requests
    pip install --upgrade requests

Ruby

لتشغيل نماذج التعليمات البرمجية Ruby في هذا المستند، ستحتاج إلى:

  • Ruby 2.6 أو أحدث
  • مكتبة مصادقة Google للغة Ruby:

    gem install googleauth
  • إطار عمل تطبيق الويب Sinatra Ruby.

    gem install sinatra

Node.js

لتشغيل نماذج رمز Node.js في هذا المستند، ستحتاج إلى ما يلي:

  • قناة الدعم الطويل الأمد (LTS) أو قناة الدعم الطويل الأمد (LTS) أو الإصدار الحالي من Node.js
  • عميل Node.js في Google APIs:

    npm install googleapis

HTTP/REST

لا تحتاج إلى تثبيت أي مكتبات لتتمكّن من طلب نقاط نهاية OAuth 2.0 مباشرةً.

الحصول على رموز الدخول عبر OAuth 2.0

توضِّح الخطوات التالية كيفية تفاعل تطبيقك مع خادم OAuth 2.0 من Google للحصول على موافقة المستخدم على تنفيذ طلب بيانات من واجهة برمجة التطبيقات نيابةً عن المستخدم. يجب أن يحصل تطبيقك على هذه الموافقة حتى يتمكّن من تنفيذ طلب من Google API يتطلّب الحصول على إذن من المستخدم.

تلخص القائمة أدناه هذه الخطوات بسرعة:

  1. ويحدِّد التطبيق الأذونات التي يحتاج إليها.
  2. يُعيد تطبيقك توجيه المستخدم إلى Google مع قائمة الأذونات المطلوبة.
  3. يقرر المستخدم ما إذا كان سيمنح الأذونات لتطبيقك أم لا.
  4. يكتشف تطبيقك ما قرره المستخدم.
  5. إذا منَح المستخدم الأذونات المطلوبة، يسترد تطبيقك الرموز المميّزة اللازمة لإجراء طلبات البيانات من واجهة برمجة التطبيقات نيابةً عن المستخدم.

الخطوة 1: ضبط مَعلمات التفويض

تتمثل خطوتك الأولى في إنشاء طلب التفويض. ويحدّد ذلك الطلب معلَمات تحدّد تطبيقك وتحدِّد الأذونات التي سيُطلَب من المستخدم منحها لتطبيقك.

  • إذا كنت تستخدم مكتبة برامج Google لمصادقة وتفويض OAuth 2.0، يمكنك إنشاء وإعداد كائن يحدد هذه المَعلمات.
  • إذا استدعيت نقطة نهاية Google OAuth 2.0 مباشرةً، ستنشئ عنوان URL وتضبط المعلَمات على عنوان URL هذا.

تحدد علامات التبويب أدناه معلمات التفويض المتوافقة لتطبيقات خادم الويب. وتوضّح الأمثلة بلغات معيّنة أيضًا كيفية استخدام مكتبة برامج أو مكتبة تفويض لإعداد عنصر يحدّد هذه المَعلمات.

PHP

ينشئ مقتطف الرمز أدناه كائن Google\Client() يحدد المَعلمات في طلب التفويض.

ويستخدم هذا الكائن معلومات من ملف client_secret.json لتحديد تطبيقك. (راجع إنشاء بيانات اعتماد التفويض للحصول على مزيد من المعلومات حول هذا الملف). يحدد الكائن أيضًا النطاقات التي يطلب تطبيقك إذنًا للوصول إليها وعنوان URL لنقطة نهاية المصادقة للتطبيق، والتي ستتعامل مع الاستجابة من خادم OAuth 2.0 من Google. أخيرًا، يحدّد الرمز المَعلمتَين access_type وinclude_granted_scopes الاختياريتَين.

على سبيل المثال، يطلب هذا الرمز إذنًا بالقراءة فقط بلا إنترنت إلى Google Drive الخاص بالمستخدم:

$client = new Google\Client();

// Required, call the setAuthConfig function to load authorization credentials from
// client_secret.json file.
$client->setAuthConfig('client_secret.json');

// Required, to set the scope value, call the addScope function
$client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY);

// Required, call the setRedirectUri function to specify a valid redirect URI for the
// provided client_id
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');

// Recommended, offline access will give you both an access and refresh token so that
// your app can refresh the access token without user interaction.
$client->setAccessType('offline');

// Recommended, call the setState function. Using a state value can increase your assurance that
// an incoming connection is the result of an authentication request.
$client->setState($sample_passthrough_value);

// Optional, if your application knows which user is trying to authenticate, it can use this
// parameter to provide a hint to the Google Authentication Server.
$client->setLoginHint('hint@example.com');

// Optional, call the setPrompt function to set "consent" will prompt the user for consent
$client->setPrompt('consent');

// Optional, call the setIncludeGrantedScopes function with true to enable incremental
// authorization
$client->setIncludeGrantedScopes(true);

Python

يستخدم مقتطف الرمز التالي وحدة google-auth-oauthlib.flow لإنشاء طلب التفويض.

ينشئ الرمز كائن Flow يحدّد تطبيقك باستخدام معلومات من ملف client_secret.json الذي نزّلته بعد إنشاء بيانات اعتماد التفويض. ويحدد ذلك الكائن أيضًا النطاقات التي يطلب التطبيق إذنًا للوصول إليها وعنوان URL لنقطة نهاية المصادقة في تطبيقك، والتي ستتعامل مع الاستجابة من خادم OAuth 2.0 من Google. أخيرًا، يحدّد الرمز المَعلمتَين access_type وinclude_granted_scopes الاختياريتَين.

على سبيل المثال، يطلب هذا الرمز إذنًا بالقراءة فقط بلا إنترنت إلى Google Drive الخاص بالمستخدم:

import google.oauth2.credentials
import google_auth_oauthlib.flow

# Required, call the from_client_secrets_file method to retrieve the client ID from a
# client_secret.json file. The client ID (from that file) and access scopes are required. (You can
# also use the from_client_config method, which passes the client configuration as it originally
# appeared in a client secrets file but doesn't access the file itself.)
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'])

# Required, indicate where the API server will redirect the user after the user completes
# the authorization flow. The redirect URI is required. The value must exactly
# match one of the authorized redirect URIs for the OAuth 2.0 client, which you
# configured in the API Console. If this value doesn't match an authorized URI,
# you will get a 'redirect_uri_mismatch' error.
flow.redirect_uri = 'https://www.example.com/oauth2callback'

# Generate URL for request to Google's OAuth 2.0 server.
# Use kwargs to set optional request parameters.
authorization_url, state = flow.authorization_url(
    # Recommended, enable offline access so that you can refresh an access token without
    # re-prompting the user for permission. Recommended for web server apps.
    access_type='offline',
    # Optional, enable incremental authorization. Recommended as a best practice.
    include_granted_scopes='true',
    # Recommended, state value can increase your assurance that an incoming connection is the result
    # of an authentication request.
    state=sample_passthrough_value,
    # Optional, if your application knows which user is trying to authenticate, it can use this
    # parameter to provide a hint to the Google Authentication Server.
    login_hint='hint@example.com',
    # Optional, set prompt to 'consent' will prompt the user for consent
    prompt='consent')

Ruby

استخدِم ملف client_secrets.json الذي أنشأته لإعداد كائن عميل في تطبيقك. عند ضبط كائن عميل، يمكنك تحديد النطاقات التي يحتاج تطبيقك إلى الوصول إليها، بالإضافة إلى عنوان URL لنقطة نهاية المصادقة للتطبيق، والتي ستتعامل مع الاستجابة من خادم OAuth 2.0.

على سبيل المثال، يطلب هذا الرمز إذنًا بالقراءة فقط بلا إنترنت إلى Google Drive الخاص بالمستخدم:

require 'google/apis/drive_v3'
require "googleauth"
require 'googleauth/stores/redis_token_store'

client_id = Google::Auth::ClientId.from_file('/path/to/client_secret.json')
scope = 'https://www.googleapis.com/auth/drive.metadata.readonly'
token_store = Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)
authorizer = Google::Auth::WebUserAuthorizer.new(client_id, scope, token_store, '/oauth2callback')

يستخدم تطبيقك كائن العميل لتنفيذ عمليات OAuth 2.0، مثل إنشاء عناوين URL لطلبات التفويض وتطبيق رموز الدخول على طلبات HTTP.

Node.js

ينشئ مقتطف الرمز أدناه كائن google.auth.OAuth2 يحدد المَعلمات في طلب التفويض.

ويستخدم هذا الكائن معلومات من ملف client_secret.json لتحديد تطبيقك. لطلب الحصول على أذونات من المستخدم لاسترداد رمز الدخول، عليك إعادة توجيهه إلى صفحة موافقة. لإنشاء عنوان URL لصفحة الموافقة:

const {google} = require('googleapis');

/**
 * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI
 * from the client_secret.json file. To get these credentials for your application, visit
 * https://console.cloud.google.com/apis/credentials.
 */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for read-only Drive activity.
const scopes = [
  'https://www.googleapis.com/auth/drive.metadata.readonly'
];

// Generate a url that asks permissions for the Drive activity scope
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  /** Pass in the scopes array defined above.
    * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
  scope: scopes,
  // Enable incremental authorization. Recommended as a best practice.
  include_granted_scopes: true
});

ملاحظة مهمة: لا يتم إرجاع refresh_token إلا عند الحصول على الإذن الأول. يمكنك الاطّلاع على مزيد من التفاصيل هنا.

HTTP/REST

نقطة نهاية OAuth 2.0 من Google في https://accounts.google.com/o/oauth2/v2/auth. لا يمكن الوصول إلى نقطة النهاية هذه إلا من خلال HTTPS. تم رفض اتصالات HTTP البسيطة.

يتيح خادم تفويض Google استخدام معلَمات سلسلة طلب البحث التالية لتطبيقات خادم الويب:

المَعلمات
client_id مطلوب

معرِّف العميل لتطبيقك. يمكنك العثور على هذه القيمة في Credentials page API Console.

redirect_uri مطلوب

تحدد هذه السمة المكان الذي يُعيد فيه خادم واجهة برمجة التطبيقات توجيه المستخدم بعد أن يُكمل عملية التفويض. يجب أن تتطابق القيمة تمامًا مع أحد معرّفات الموارد المنتظمة (URI) المعتمَدة لإعادة التوجيه في برنامج OAuth 2.0، والذي ضبطته في Credentials page API Consoleللبرنامج. وإذا لم تتطابق هذه القيمة مع معرّف الموارد المنتظم (URI) المعتمَد لإعادة التوجيه للسمة client_id المقدّمة، سيظهر لك خطأ redirect_uri_mismatch.

يُرجى العلم أنّه يجب أن تتطابق جميع العناصر في نظام http أو https مع حالة الأحرف والشرطة المائلة اللاحقة ('/).

response_type مطلوب

تحدِّد نقطة نهاية Google OAuth 2.0 ما إذا كانت تعرض رمز تفويض أم لا.

اضبط قيمة المعلَمة على code لتطبيقات خادم الويب.

scope مطلوب

يشير ذلك إلى قائمة بالنطاقات التي يتم الفصل بينها بمسافات والتي تحدّد الموارد التي يمكن للتطبيق الوصول إليها نيابةً عن المستخدم. وتوضّح هذه القيم شاشة طلب الموافقة التي تعرضها Google للمستخدم.

تتيح النطاقات لتطبيقك إمكانية طلب الوصول إلى الموارد التي يحتاجها فقط، مع السماح للمستخدمين في الوقت نفسه بالتحكم في مستوى الوصول الذي يتم منحه لتطبيقك. وبالتالي، هناك علاقة عكسية بين عدد النطاقات المطلوبة واحتمالية الحصول على موافقة المستخدم.

ننصحك بأن يطلب تطبيقك الوصول إلى نطاقات التفويض في السياق كلما أمكن ذلك. من خلال طلب الوصول إلى بيانات المستخدمين في السياق المناسب، من خلال الإذن المتزايد، تساعد المستخدمين على فهم سبب احتياج تطبيقك إلى إذن الوصول الذي يطلبه.

access_type سمة مقترَحة

يشير إلى ما إذا كان بإمكان تطبيقك إعادة تحميل رموز الدخول عند عدم تواجد المستخدم في المتصفح. قيم المَعلمات الصالحة هي online، وهي القيمة التلقائية، وoffline.

اضبط القيمة على offline إذا كان تطبيقك يحتاج إلى إعادة تحميل رموز الدخول عندما لا يكون المستخدم متاحًا في المتصفح. هذه هي طريقة إعادة تحميل رموز الدخول الموضّحة لاحقًا في هذا المستند. تُوجِّه هذه القيمة خادم تفويض Google لعرض رمز مميز لإعادة التحميل ورمز دخول في المرّة الأولى التي يتبادل فيها تطبيقك رمز تفويض بالرموز المميّزة.

state سمة مقترَحة

يحدد أي قيمة سلسلة يستخدمها تطبيقك للحفاظ على الحالة بين طلب التفويض واستجابة خادم التفويض. يعرض الخادم القيمة الدقيقة التي ترسلها كزوج name=value في مكوّن طلب البحث لعنوان URL (?) في redirect_uri بعد موافقة المستخدم على طلب الوصول إلى تطبيقك أو رفضه.

يمكنك استخدام هذه المَعلمة لأغراض متعدّدة، مثل توجيه المستخدم إلى المورد الصحيح في تطبيقك، وإرسال أرقام خاصة، والتخفيف من حدّة تزوير الطلبات من مواقع إلكترونية متعددة. بما أنّه يمكن تخمين redirect_uri، يمكن أن يؤدي استخدام قيمة state إلى زيادة ضمانك بأنّ الاتصال الوارد هو نتيجة طلب مصادقة. في حال إنشاء سلسلة عشوائية أو ترميز تجزئة ملف تعريف ارتباط أو قيمة أخرى تسجِّل حالة العميل، يمكنك التحقّق من الاستجابة لضمان أنّ الطلب والاستجابة صادران في المتصفّح نفسه لتوفير الحماية ضد الهجمات، مثل تزوير الطلبات من عدة مواقع إلكترونية. يمكنك الاطّلاع على مستندات OpenID Connect للحصول على مثال حول كيفية إنشاء رمز مميَّز لـ state وتأكيده.

include_granted_scopes اختياريّ

يسمح هذا الإعداد للتطبيقات باستخدام التفويض المتزايد لطلب الوصول إلى نطاقات إضافية في السياق. في حال ضبط قيمة هذه المعلَمة على true وتم منح طلب التفويض، سيغطي رمز الدخول الجديد أيضًا أي نطاقات منحها المستخدم في السابق إذن الوصول إلى التطبيق. راجِع قسم التفويض المتزايد للحصول على أمثلة.

login_hint اختياريّ

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

اضبط قيمة المعلَمة على عنوان بريد إلكتروني أو معرّف sub، أي ما يعادل معرّف Google للمستخدم.

prompt اختياريّ

قائمة بطلبات تقديم المستخدم محددة بمسافات وحساسة لحالة الأحرف. إذا لم تحدّد هذه المَعلمة، سيُطلب من المستخدم فقط في المرة الأولى التي يطلب فيها مشروعك الوصول إلى البيانات. راجِع طلب إعادة الموافقة للحصول على مزيد من المعلومات.

القيم المتاحة:

none لا تعرض أي شاشات للمصادقة أو طلب موافقة. يجب عدم تحديدها مع قيم أخرى.
consent طلب الموافقة من المستخدم
select_account مطالبة المستخدم باختيار حساب

الخطوة 2: إعادة التوجيه إلى خادم OAuth 2.0 من Google

أعِد توجيه المستخدم إلى خادم OAuth 2.0 من Google لبدء عملية المصادقة والترخيص. ويحدث ذلك عادةً عندما يحتاج تطبيقك أولاً إلى الوصول إلى بيانات المستخدم. في حالة التفويض المتزايد، تحدث هذه الخطوة أيضًا عندما يحتاج التطبيق أولاً إلى الوصول إلى موارد إضافية ليس لديه إذن بالوصول إليها بعد.

PHP

  1. إنشاء عنوان URL لطلب الوصول من خادم OAuth 2.0 من Google:
    $auth_url = $client->createAuthUrl();
  2. إعادة توجيه المستخدم إلى $auth_url:
    header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));

Python

يوضّح هذا المثال كيفية إعادة توجيه المستخدم إلى عنوان URL للتفويض باستخدام إطار عمل تطبيق الويب Flask:

return flask.redirect(authorization_url)

Ruby

  1. إنشاء عنوان URL لطلب الوصول من خادم OAuth 2.0 من Google:
    auth_uri = authorizer.get_authorization_url(login_hint: user_id, request: request)
  2. إعادة توجيه المستخدم إلى auth_uri.

Node.js

  1. يمكنك استخدام عنوان URL الذي تم إنشاؤه authorizationUrl من الخطوة 1 generateAuthUrl لطلب الوصول من خادم OAuth 2.0 في Google.
  2. إعادة توجيه المستخدم إلى authorizationUrl.
    res.writeHead(301, { "Location": authorizationUrl });

HTTP/REST

Sample redirect to Google's authorization server

An example URL is shown below, with line breaks and spaces for readability.

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 access_type=offline&
 include_granted_scopes=true&
 response_type=code&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id

بعد إنشاء عنوان URL للطلب، أعِد توجيه المستخدم إليه.

ويعمل خادم OAuth 2.0 من Google على مصادقة المستخدم ويحصل على موافقة المستخدم في ما يتعلّق بتطبيقك للوصول إلى النطاقات المطلوبة. يتم إرسال الرد إلى تطبيقك باستخدام عنوان URL الذي حددته لإعادة التوجيه.

الخطوة 3: تطلب Google من المستخدم الموافقة

في هذه الخطوة، يقرّر المستخدم ما إذا كان سيمنح تطبيقك إذن الوصول المطلوب. في هذه المرحلة، تعرض Google نافذة موافقة تعرض اسم تطبيقك وخدمات Google API التي تطلب إذنًا للوصول إليها، وذلك باستخدام بيانات اعتماد التفويض الخاصة بالمستخدم وملخّصًا لنطاقات إمكانية الوصول التي سيتم منحها. يمكن للمستخدم بعد ذلك الموافقة على منح إذن الوصول إلى نطاق واحد أو أكثر من النطاقات التي يطلبها طلبك أو رفض الطلب.

لا يحتاج تطبيقك إلى تنفيذ أي إجراء في هذه المرحلة، لأنّه ينتظر ردًّا من خادم OAuth 2.0 من Google للإشارة إلى ما إذا كان قد تم منح أي إذن دخول. يتم شرح هذه الإجابة في الخطوة التالية.

الأخطاء

قد تعرض الطلبات المُرسَلة إلى نقطة نهاية تفويض OAuth 2.0 من Google رسائل خطأ موجّهة للمستخدمين بدلاً من تدفقات المصادقة والتفويض المتوقعة. تم إدراج رموز الأخطاء الشائعة والحلول المقترَحة أدناه.

admin_policy_enforced

يتعذّر على حساب Google تفويض نطاق واحد أو أكثر مطلوب بسبب سياسات مشرف Google Workspace. يمكنك الاطّلاع على مقالة مساعدة مشرف Google Workspace التحكّم في التطبيقات التابعة لجهات خارجية والتطبيقات الداخلية التي يمكنها الوصول إلى بيانات Google Workspace للحصول على مزيد من المعلومات حول الطريقة التي قد يتّبعها المشرف لحظر الوصول إلى جميع النطاقات أو النطاقات الحسّاسة والمحظورة، إلى أن يتم منح الإذن بالوصول صراحةً إلى معرّف عميل OAuth.

disallowed_useragent

يتم عرض نقطة نهاية التفويض داخل وكيل مستخدم مضمّن لا تسمح به سياسات OAuth 2.0 في Google.

Android

قد تظهر رسالة الخطأ هذه لمطوّري برامج Android عند فتح طلبات التفويض في android.webkit.WebView. وبدلاً من ذلك، على المطوّرين استخدام مكتبات Android، مثل ميزة "تسجيل الدخول بحساب Google" لأجهزة Android أو AppAuth لنظام التشغيل Android من OpenID Foundation.

قد يظهر هذا الخطأ لمطوّري البرامج على الويب عندما يفتح تطبيق Android رابط ويب عامًا في وكيل مستخدم مضمّن وينتقل مستخدم إلى نقطة نهاية تفويض OAuth 2.0 من Google من موقعك الإلكتروني. على المطوّرين السماح بفتح الروابط العامة في المعالج التلقائي للروابط في نظام التشغيل، والذي يتضمّن معالِجات روابط تطبيقات Android أو تطبيق المتصفّح التلقائي. ويمكن أيضًا استخدام مكتبة علامات التبويب المخصّصة في Android.

iOS

قد يظهر هذا الخطأ لمطوّري تطبيقات iOS وmacOS عند فتح طلبات التفويض في WKWebView. وبدلاً من ذلك، على المطوّرين استخدام مكتبات iOS مثل تسجيل الدخول بحساب Google لنظام التشغيل iOS أو AppAuth for iOS من OpenID Foundation.

قد يظهر هذا الخطأ لمطوّري البرامج على الويب عندما يفتح أحد تطبيقات iOS أو macOS رابط ويب عامًا في وكيل مستخدم مضمّن وينتقل مستخدم إلى نقطة نهاية تفويض OAuth 2.0 من Google من موقعك الإلكتروني. على المطوّرين السماح بفتح الروابط العامة في المعالج التلقائي للروابط في نظام التشغيل، والذي يتضمّن معالِجات الروابط العامة أو تطبيق المتصفّح التلقائي. ويمكن أيضًا استخدام مكتبة SFSafariViewController.

org_internal

يمثّل معرّف عميل OAuth في الطلب جزءًا من مشروع يحدّ من الوصول إلى حسابات Google في مؤسسة Google Cloud معيّنة. للاطّلاع على مزيد من المعلومات حول خيار الإعداد هذا، راجِع القسم نوع المستخدم في مقالة المساعدة "إعداد شاشة طلب الموافقة المتعلّقة ببروتوكول OAuth".

invalid_client

سر عميل OAuth غير صحيح. راجِع إعدادات عميل OAuth، بما في ذلك معرِّف العميل وسر العميل المستخدَم في هذا الطلب.

invalid_grant

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

redirect_uri_mismatch

لا يتطابق redirect_uri الذي تم تمريره في طلب التفويض مع معرّف الموارد المنتظم (URI) المعتمد لإعادة التوجيه لمعرّف عميل OAuth. راجِع معرِّفات الموارد المنتظمة (URI) المعتمَدة لإعادة التوجيه في Google API Console Credentials page.

قد تشير المَعلمة redirect_uri إلى مسار OAuth خارج النطاق (OOB) الذي تم إيقافه نهائيًا ولم يعُد متوافقًا. يُرجى مراجعة دليل نقل البيانات لتعديل عملية الدمج.

invalid_request

حدث خطأ في الطلب الذي قدّمته. قد يرجع ذلك إلى عدة أسباب:

  • لم يتم تنسيق الطلب بشكلٍ صحيح
  • كان الطلب يفتقد إلى المعلمات المطلوبة
  • يستخدم الطلب طريقة تفويض لا تتوافق مع Google. تأكَّد من أنّ عملية دمج OAuth تستخدم إحدى طرق الدمج المقترَحة.

الخطوة 4: التعامل مع استجابة خادم OAuth 2.0

يستجيب خادم OAuth 2.0 لطلب الوصول إلى تطبيقك باستخدام عنوان URL المحدَّد في الطلب.

إذا وافق المستخدم على طلب الوصول، ستحتوي الاستجابة على رمز التفويض. وإذا لم يوافق المستخدم على الطلب، ستظهر رسالة خطأ في الردّ. يظهر رمز التفويض أو رسالة الخطأ التي يتم عرضها إلى خادم الويب في سلسلة طلب البحث، كما هو موضّح أدناه:

الردّ على رسالة الخطأ:

https://oauth2.example.com/auth?error=access_denied

استجابة رمز التفويض:

https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7

نموذج لاستجابة خادم OAuth 2.0

يمكنك اختبار هذا المسار بالنقر على نموذج عنوان URL التالي، والذي يطلب الإذن بالقراءة فقط لعرض البيانات الوصفية للملفات في Google Drive:

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 access_type=offline&
 include_granted_scopes=true&
 response_type=code&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id

بعد إكمال مسار OAuth 2.0، من المفترَض أن تتم إعادة توجيهك إلى http://localhost/oauth2callback، ما قد يؤدي إلى ظهور الخطأ 404 NOT FOUND ما لم يعرض جهازك المحلي ملفًا على هذا العنوان. وتقدم الخطوة التالية مزيدًا من التفاصيل حول المعلومات التي يتم عرضها في معرّف الموارد المنتظم (URI) عند إعادة توجيه المستخدم إلى تطبيقك.

الخطوة 5: تبادل رمز التفويض لرموز إعادة التحميل والدخول

بعد أن يتلقى خادم الويب رمز التفويض، يمكنه استبدال رمز التفويض برمز دخول.

PHP

لاستبدال رمز التفويض برمز دخول، استخدِم الطريقة authenticate:

$client->authenticate($_GET['code']);

يمكنك استرداد رمز الدخول باستخدام طريقة getAccessToken:

$access_token = $client->getAccessToken();

Python

في صفحة معاودة الاتصال، استخدِم مكتبة google-auth للتحقّق من استجابة خادم التفويض. بعد ذلك، استخدِم طريقة flow.fetch_token لاستبدال رمز التفويض في هذه الاستجابة برمز دخول:

state = flask.session['state']
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'],
    state=state)
flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

authorization_response = flask.request.url
flow.fetch_token(authorization_response=authorization_response)

# Store the credentials in the session.
# ACTION ITEM for developers:
#     Store user's access and refresh tokens in your data store if
#     incorporating this code into your real app.
credentials = flow.credentials
flask.session['credentials'] = {
    'token': credentials.token,
    'refresh_token': credentials.refresh_token,
    'token_uri': credentials.token_uri,
    'client_id': credentials.client_id,
    'client_secret': credentials.client_secret,
    'scopes': credentials.scopes}

Ruby

في صفحة معاودة الاتصال، استخدِم مكتبة googleauth للتحقّق من استجابة خادم التفويض. استخدِم الطريقة authorizer.handle_auth_callback_deferred لحفظ رمز التفويض وإعادة التوجيه إلى عنوان URL الذي طلب التفويض في الأصل. يعمل ذلك على تأجيل تبادل الرمز عن طريق التخزين المؤقت للنتائج في جلسة المستخدم.

  target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
  redirect target_url

Node.js

لاستبدال رمز التفويض برمز دخول، استخدِم الطريقة getToken:

const url = require('url');

// Receive the callback from Google's OAuth 2.0 server.
if (req.url.startsWith('/oauth2callback')) {
  // Handle the OAuth 2.0 server response
  let q = url.parse(req.url, true).query;

  // Get access and refresh tokens (if access_type is offline)
  let { tokens } = await oauth2Client.getToken(q.code);
  oauth2Client.setCredentials(tokens);
}

HTTP/REST

لاستبدال رمز تفويض برمز دخول، يمكنك طلب نقطة النهاية https://oauth2.googleapis.com/token وضبط المَعلمات التالية:

الحقول
client_id رقم تعريف العميل الذي تم الحصول عليه من API Console Credentials page.
client_secret سر العميل الذي تم الحصول عليه من API Console Credentials page.
code رمز التفويض الذي تم عرضه من الطلب الأولي
grant_type كما هو موضّح في مواصفات OAuth 2.0، يجب ضبط قيمة هذا الحقل على authorization_code.
redirect_uri يشير هذا المصطلح إلى أحد معرّفات الموارد المنتظمة (URI) لإعادة التوجيه المدرَجة لمشروعك في API Console Credentials page لمعرّف client_id المحدَّد.

يعرض المقتطف التالي نموذجًا للطلب:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=https%3A//oauth2.example.com/code&
grant_type=authorization_code

يستجيب محرّك بحث Google لهذا الطلب من خلال عرض عنصر JSON يحتوي على رمز دخول قصير الأجل ورمز مميّز لإعادة التحميل. يُرجى العِلم أنّه لا يتم عرض الرمز المميّز لإعادة التحميل إلا إذا ضبط تطبيقك المعلَمة access_type على offline في الطلب الأوّلي الذي يتم إرساله إلى خادم التفويض في Google.

ويحتوي الرد على الحقول التالية:

الحقول
access_token الرمز المميّز الذي يرسله تطبيقك لتفويض طلب من واجهة Google API
expires_in المدة المتبقية لرمز الدخول بالثواني.
refresh_token يشير هذا المصطلح إلى رمز يمكنك استخدامه للحصول على رمز دخول جديد. وتكون الرموز المميّزة لإعادة التحميل صالحة إلى أن يُبطِل المستخدم إذن الوصول. ومرة أخرى، لا يتوفّر هذا الحقل في هذه الاستجابة إلا في حال ضبط المَعلمة access_type على offline في الطلب الأوّلي إلى خادم التفويض من Google.
scope نطاقات الوصول التي تمنحها access_token، ويتم التعبير عنها في شكل قائمة من سلاسل حساسة لحالة الأحرف ويتم الفصل بينها بمسافات.
token_type نوع الرمز المميّز الذي تم عرضه. في الوقت الحالي، يتم ضبط قيمة هذا الحقل دائمًا على Bearer.

يعرض المقتطف التالي نموذجًا للرد:

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "token_type": "Bearer",
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
  "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

الأخطاء

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

invalid_grant

رمز التفويض المقدَّم غير صالح أو بتنسيق غير صحيح. اطلب رمزًا جديدًا من خلال إعادة بدء عملية OAuth لطلب الموافقة من المستخدم مرة أخرى.

طلب بيانات من Google APIs

PHP

استخدم رمز الدخول لطلب Google APIs من خلال إكمال الخطوات التالية:

  1. إذا كنت بحاجة إلى تطبيق رمز الدخول على عنصر Google\Client جديد، على سبيل المثال، إذا خزّنت رمز الدخول في جلسة مستخدم، يمكنك استخدام طريقة setAccessToken:
    $client->setAccessToken($access_token);
  2. أنشئ عنصر خدمة لواجهة برمجة التطبيقات التي تريد طلبها. يمكنك إنشاء عنصر خدمة من خلال توفير عنصر Google\Client معتمد للدالة الإنشائية لواجهة برمجة التطبيقات التي تريد طلبها. على سبيل المثال، لطلب البيانات من Drive API:
    $drive = new Google\Service\Drive($client);
  3. يمكنك تقديم طلبات إلى خدمة واجهة برمجة التطبيقات باستخدام الواجهة التي يوفّرها عنصر الخدمة. على سبيل المثال، لإدراج الملفات في Google Drive الخاص بالمستخدم الذي تمت المصادقة عليه:
    $files = $drive->files->listFiles(array())->getItems();

Python

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

  1. أنشئ عنصر خدمة لواجهة برمجة التطبيقات التي تريد طلبها. يمكنك إنشاء عنصر خدمة من خلال طلب طريقة build في مكتبة googleapiclient.discovery مع اسم واجهة برمجة التطبيقات وإصدارها وبيانات اعتماد المستخدم: على سبيل المثال، لطلب الإصدار 3 من Drive API:
    from googleapiclient.discovery import build
    
    drive = build('drive', 'v2', credentials=credentials)
  2. يمكنك تقديم طلبات إلى خدمة واجهة برمجة التطبيقات باستخدام الواجهة التي يوفّرها عنصر الخدمة. على سبيل المثال، لإدراج الملفات في Google Drive الخاص بالمستخدم الذي تمت المصادقة عليه:
    files = drive.files().list().execute()

Ruby

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

  1. أنشئ عنصر خدمة لواجهة برمجة التطبيقات التي تريد طلبها. على سبيل المثال، لطلب الإصدار 3 من Drive API:
    drive = Google::Apis::DriveV3::DriveService.new
  2. اضبط بيانات الاعتماد في الخدمة:
    drive.authorization = credentials
  3. يمكنك تقديم طلبات إلى خدمة واجهة برمجة التطبيقات باستخدام الواجهة التي يوفّرها عنصر الخدمة. على سبيل المثال، لإدراج الملفات في Google Drive الخاص بالمستخدم الذي تمت المصادقة عليه:
    files = drive.list_files

يمكن بدلاً من ذلك توفير التفويض على أساس كل طريقة من خلال توفير المَعلمة options إلى إحدى الطرق التالية:

files = drive.list_files(options: { authorization: credentials })

Node.js

بعد الحصول على رمز الدخول وضبطه في الكائن OAuth2، استخدِم الكائن لاستدعاء Google APIs. يمكن لتطبيقك استخدام هذا الرمز المميّز للسماح بتنفيذ طلبات البيانات من واجهة برمجة التطبيقات نيابةً عن حساب مستخدم أو حساب خدمة معيّن. أنشئ عنصر خدمة لواجهة برمجة التطبيقات التي تريد طلبها.

const { google } = require('googleapis');

// Example of using Google Drive API to list filenames in user's Drive.
const drive = google.drive('v3');
drive.files.list({
  auth: oauth2Client,
  pageSize: 10,
  fields: 'nextPageToken, files(id, name)',
}, (err1, res1) => {
  if (err1) return console.log('The API returned an error: ' + err1);
  const files = res1.data.files;
  if (files.length) {
    console.log('Files:');
    files.map((file) => {
      console.log(`${file.name} (${file.id})`);
    });
  } else {
    console.log('No files found.');
  }
});

HTTP/REST

بعد حصول تطبيقك على رمز دخول، يمكنك استخدام الرمز المميّز لإجراء طلبات بيانات من Google API نيابةً عن حساب مستخدم معيّن، وذلك في حال تم منح نطاقات الوصول التي تطلبها واجهة برمجة التطبيقات. لإجراء ذلك، ضمِّن رمز الدخول في طلب لواجهة برمجة التطبيقات عن طريق تضمين مَعلمة طلب بحث access_token أو قيمة Bearer لعنوان HTTP Authorization. ويفضَّل استخدام عنوان HTTP إذا أمكن، لأنّ سلاسل الطلبات تكون غالبًا مرئية في سجلات الخادم. وفي معظم الحالات، يمكنك استخدام مكتبة برامج لإعداد طلباتك المتعلّقة بواجهات Google APIs (على سبيل المثال، عند طلب واجهة برمجة التطبيقات Drive Files API).

ويمكنك تجربة جميع واجهات برمجة تطبيقات Google وعرض نطاقاتها في ملعب OAuth 2.0.

أمثلة على HTTP GET

قد يبدو طلب نقطة نهاية drive.files (واجهة برمجة تطبيقات ملفات Drive) باستخدام عنوان HTTP Authorization: Bearer على النحو التالي. لاحظ أنك تحتاج إلى تحديد رمز الدخول الخاص بك:

GET /drive/v2/files HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

في ما يلي طلب بيانات من واجهة برمجة التطبيقات نفسها للمستخدِم الذي تمت مصادقته باستخدام معلَمة سلسلة طلب البحث access_token:

GET https://www.googleapis.com/drive/v2/files?access_token=access_token

أمثلة على curl

ويمكنك اختبار هذه الأوامر باستخدام تطبيق سطر الأوامر curl. في ما يلي مثال يستخدم خيار عنوان HTTP (الخيار المفضّل):

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files

أو بدلاً من ذلك، خيار معلمة سلسلة طلب البحث:

curl https://www.googleapis.com/drive/v2/files?access_token=access_token

مثال مكتمل

يطبع المثال التالي قائمة ملفات بتنسيق JSON في Google Drive للمستخدم بعد أن يجري المستخدم مصادقة ويمنح التطبيق الموافقة على الوصول إلى البيانات الوصفية في Drive للمستخدم.

PHP

لتشغيل هذا المثال:

  1. في API Console، أضِف عنوان URL الخاص بالجهاز المحلي إلى قائمة عناوين URL لإعادة التوجيه. على سبيل المثال، أضِف http://localhost:8080.
  2. أنشئ دليلاً جديدًا وغيّره. مثلاً:
    mkdir ~/php-oauth2-example
    cd ~/php-oauth2-example
  3. ثبِّت مكتبة برامج Google API للغة PHP باستخدام Composer:
    composer require google/apiclient:^2.10
  4. أنشئ الملفين index.php وoauth2callback.php باستخدام المحتوى أدناه.
  5. شغِّل المثال مع خادم ويب تم إعداده لعرض لغة PHP. إذا كنت تستخدم الإصدار 5.6 من PHP أو إصدارًا أحدث، يمكنك استخدام خادم الويب التجريبي المدمج في PHP:
    php -S localhost:8080 ~/php-oauth2-example

index.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google\Client();
$client->setAuthConfig('client_secrets.json');
$client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY);

if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
  $client->setAccessToken($_SESSION['access_token']);
  $drive = new Google\Service\Drive($client);
  $files = $drive->files->listFiles(array())->getItems();
  echo json_encode($files);
} else {
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

oauth2callback.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google\Client();
$client->setAuthConfigFile('client_secrets.json');
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
$client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY);

if (! isset($_GET['code'])) {
  $auth_url = $client->createAuthUrl();
  header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
  $client->authenticate($_GET['code']);
  $_SESSION['access_token'] = $client->getAccessToken();
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

Python

يستخدم هذا المثال إطار عمل Flask. يشغّل تطبيق ويب على http://localhost:8080 يتيح لك اختبار مسار OAuth 2.0. إذا انتقلت إلى عنوان URL هذا، من المفترض أن ترى أربعة روابط:

  • اختبار طلب بيانات من واجهة برمجة التطبيقات: يشير هذا الرابط إلى صفحة تحاول تنفيذ نموذج لطلب بيانات من واجهة برمجة التطبيقات. وعند الضرورة، يبدأ تدفق التفويض. في حال نجاح هذا الإجراء، ستعرض الصفحة الردّ من واجهة برمجة التطبيقات.
  • اختبار مسار المصادقة مباشرةً: يشير هذا الرابط إلى صفحة تحاول إرسال المستخدم من خلال مسار التفويض. يطلب التطبيق إذنًا لإرسال طلبات مصرَّح بها من واجهة برمجة التطبيقات نيابةً عن المستخدم.
  • إبطال بيانات الاعتماد الحالية: يشير هذا الرابط إلى صفحة تُبطِل الأذونات التي سبق أن منحها المستخدم للتطبيق.
  • محو بيانات اعتماد جلسة Flask: يمحو هذا الرابط بيانات اعتماد التفويض المخزّنة في جلسة Flask. يتيح لك ذلك معرفة ما سيحدث إذا حاول مستخدم سبق له منح الإذن لتطبيقك تنفيذ طلب بيانات من واجهة برمجة التطبيقات في جلسة جديدة. ويتيح لك أيضًا الاطّلاع على استجابة واجهة برمجة التطبيقات التي سيحصل عليها تطبيقك إذا أبطل المستخدم الأذونات التي تم منحها له وما زال تطبيقك يحاول منح الإذن بطلب باستخدام رمز دخول تم إبطاله.
# -*- coding: utf-8 -*-

import os
import flask
import requests

import google.oauth2.credentials
import google_auth_oauthlib.flow
import googleapiclient.discovery

# This variable specifies the name of a file that contains the OAuth 2.0
# information for this application, including its client_id and client_secret.
CLIENT_SECRETS_FILE = "client_secret.json"

# This OAuth 2.0 access scope allows for full read/write access to the
# authenticated user's account and requires requests to use an SSL connection.
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']
API_SERVICE_NAME = 'drive'
API_VERSION = 'v2'

app = flask.Flask(__name__)
# Note: A secret key is included in the sample so that it works.
# If you use this code in your application, replace this with a truly secret
# key. See https://flask.palletsprojects.com/quickstart/#sessions.
app.secret_key = 'REPLACE ME - this value is here as a placeholder.'


@app.route('/')
def index():
  return print_index_table()


@app.route('/test')
def test_api_request():
  if 'credentials' not in flask.session:
    return flask.redirect('authorize')

  # Load credentials from the session.
  credentials = google.oauth2.credentials.Credentials(
      **flask.session['credentials'])

  drive = googleapiclient.discovery.build(
      API_SERVICE_NAME, API_VERSION, credentials=credentials)

  files = drive.files().list().execute()

  # Save credentials back to session in case access token was refreshed.
  # ACTION ITEM: In a production app, you likely want to save these
  #              credentials in a persistent database instead.
  flask.session['credentials'] = credentials_to_dict(credentials)

  return flask.jsonify(**files)


@app.route('/authorize')
def authorize():
  # Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES)

  # The URI created here must exactly match one of the authorized redirect URIs
  # for the OAuth 2.0 client, which you configured in the API Console. If this
  # value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch'
  # error.
  flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

  authorization_url, state = flow.authorization_url(
      # Enable offline access so that you can refresh an access token without
      # re-prompting the user for permission. Recommended for web server apps.
      access_type='offline',
      # Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes='true')

  # Store the state so the callback can verify the auth server response.
  flask.session['state'] = state

  return flask.redirect(authorization_url)


@app.route('/oauth2callback')
def oauth2callback():
  # Specify the state when creating the flow in the callback so that it can
  # verified in the authorization server response.
  state = flask.session['state']

  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES, state=state)
  flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

  # Use the authorization server's response to fetch the OAuth 2.0 tokens.
  authorization_response = flask.request.url
  flow.fetch_token(authorization_response=authorization_response)

  # Store credentials in the session.
  # ACTION ITEM: In a production app, you likely want to save these
  #              credentials in a persistent database instead.
  credentials = flow.credentials
  flask.session['credentials'] = credentials_to_dict(credentials)

  return flask.redirect(flask.url_for('test_api_request'))


@app.route('/revoke')
def revoke():
  if 'credentials' not in flask.session:
    return ('You need to <a href="/authorize">authorize</a> before ' +
            'testing the code to revoke credentials.')

  credentials = google.oauth2.credentials.Credentials(
    **flask.session['credentials'])

  revoke = requests.post('https://oauth2.googleapis.com/revoke',
      params={'token': credentials.token},
      headers = {'content-type': 'application/x-www-form-urlencoded'})

  status_code = getattr(revoke, 'status_code')
  if status_code == 200:
    return('Credentials successfully revoked.' + print_index_table())
  else:
    return('An error occurred.' + print_index_table())


@app.route('/clear')
def clear_credentials():
  if 'credentials' in flask.session:
    del flask.session['credentials']
  return ('Credentials have been cleared.<br><br>' +
          print_index_table())


def credentials_to_dict(credentials):
  return {'token': credentials.token,
          'refresh_token': credentials.refresh_token,
          'token_uri': credentials.token_uri,
          'client_id': credentials.client_id,
          'client_secret': credentials.client_secret,
          'scopes': credentials.scopes}

def print_index_table():
  return ('<table>' +
          '<tr><td><a href="/test">Test an API request</a></td>' +
          '<td>Submit an API request and see a formatted JSON response. ' +
          '    Go through the authorization flow if there are no stored ' +
          '    credentials for the user.</td></tr>' +
          '<tr><td><a href="/authorize">Test the auth flow directly</a></td>' +
          '<td>Go directly to the authorization flow. If there are stored ' +
          '    credentials, you still might not be prompted to reauthorize ' +
          '    the application.</td></tr>' +
          '<tr><td><a href="/revoke">Revoke current credentials</a></td>' +
          '<td>Revoke the access token associated with the current user ' +
          '    session. After revoking credentials, if you go to the test ' +
          '    page, you should see an <code>invalid_grant</code> error.' +
          '</td></tr>' +
          '<tr><td><a href="/clear">Clear Flask session credentials</a></td>' +
          '<td>Clear the access token currently stored in the user session. ' +
          '    After clearing the token, if you <a href="/test">test the ' +
          '    API request</a> again, you should go back to the auth flow.' +
          '</td></tr></table>')


if __name__ == '__main__':
  # When running locally, disable OAuthlib's HTTPs verification.
  # ACTION ITEM for developers:
  #     When running in production *do not* leave this option enabled.
  os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'

  # Specify a hostname and port that are set as a valid redirect URI
  # for your API project in the Google API Console.
  app.run('localhost', 8080, debug=True)

Ruby

يستخدم هذا المثال إطار عمل Sinatra.

require 'google/apis/drive_v3'
require 'sinatra'
require 'googleauth'
require 'googleauth/stores/redis_token_store'

configure do
  enable :sessions

  set :client_id, Google::Auth::ClientId.from_file('/path/to/client_secret.json')
  set :scope, Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY
  set :token_store, Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)
  set :authorizer, Google::Auth::WebUserAuthorizer.new(settings.client_id, settings.scope, settings.token_store, '/oauth2callback')
end

get '/' do
  user_id = settings.client_id.id
  credentials = settings.authorizer.get_credentials(user_id, request)
  if credentials.nil?
    redirect settings.authorizer.get_authorization_url(login_hint: user_id, request: request)
  end
  drive = Google::Apis::DriveV3::DriveService.new
  files = drive.list_files(options: { authorization: credentials })
  "<pre>#{JSON.pretty_generate(files.to_h)}</pre>"
end

get '/oauth2callback' do
  target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
  redirect target_url
end

Node.js

لتشغيل هذا المثال:

  1. في API Console، أضِف عنوان URL الخاص بالجهاز المحلي إلى قائمة عناوين URL لإعادة التوجيه. على سبيل المثال، أضِف http://localhost.
  2. تأكَّد من تثبيت قناة الدعم الطويل الأمد (LTS) أو قناة الدعم الطويل الأمد (LTS) أو الإصدار الحالي من Node.js.
  3. أنشئ دليلاً جديدًا وغيّره. مثلاً:
    mkdir ~/nodejs-oauth2-example
    cd ~/nodejs-oauth2-example
  4. Install the Google API Client Library for Node.js using npm:
    npm install googleapis
  5. أنشِئ الملفات main.js باستخدام المحتوى أدناه.
  6. شغِّل المثال:
    node .\main.js

main.js

const http = require('http');
const https = require('https');
const url = require('url');
const { google } = require('googleapis');

/**
 * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI.
 * To get these credentials for your application, visit
 * https://console.cloud.google.com/apis/credentials.
 */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for read-only Drive activity.
const scopes = [
  'https://www.googleapis.com/auth/drive.metadata.readonly'
];

// Generate a url that asks permissions for the Drive activity scope
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  /** Pass in the scopes array defined above.
    * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
  scope: scopes,
  // Enable incremental authorization. Recommended as a best practice.
  include_granted_scopes: true
});

/* Global variable that stores user credential in this code example.
 * ACTION ITEM for developers:
 *   Store user's refresh token in your data store if
 *   incorporating this code into your real app.
 *   For more information on handling refresh tokens,
 *   see https://github.com/googleapis/google-api-nodejs-client#handling-refresh-tokens
 */
let userCredential = null;

async function main() {
  const server = http.createServer(async function (req, res) {
    // Example on redirecting user to Google's OAuth 2.0 server.
    if (req.url == '/') {
      res.writeHead(301, { "Location": authorizationUrl });
    }

    // Receive the callback from Google's OAuth 2.0 server.
    if (req.url.startsWith('/oauth2callback')) {
      // Handle the OAuth 2.0 server response
      let q = url.parse(req.url, true).query;

      if (q.error) { // An error response e.g. error=access_denied
        console.log('Error:' + q.error);
      } else { // Get access and refresh tokens (if access_type is offline)
        let { tokens } = await oauth2Client.getToken(q.code);
        oauth2Client.setCredentials(tokens);

        /** Save credential to the global variable in case access token was refreshed.
          * ACTION ITEM: In a production app, you likely want to save the refresh token
          *              in a secure persistent database instead. */
        userCredential = tokens;

        // Example of using Google Drive API to list filenames in user's Drive.
        const drive = google.drive('v3');
        drive.files.list({
          auth: oauth2Client,
          pageSize: 10,
          fields: 'nextPageToken, files(id, name)',
        }, (err1, res1) => {
          if (err1) return console.log('The API returned an error: ' + err1);
          const files = res1.data.files;
          if (files.length) {
            console.log('Files:');
            files.map((file) => {
              console.log(`${file.name} (${file.id})`);
            });
          } else {
            console.log('No files found.');
          }
        });
      }
    }

    // Example on revoking a token
    if (req.url == '/revoke') {
      // Build the string for the POST request
      let postData = "token=" + userCredential.access_token;

      // Options for POST request to Google's OAuth 2.0 server to revoke a token
      let postOptions = {
        host: 'oauth2.googleapis.com',
        port: '443',
        path: '/revoke',
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Content-Length': Buffer.byteLength(postData)
        }
      };

      // Set up the request
      const postReq = https.request(postOptions, function (res) {
        res.setEncoding('utf8');
        res.on('data', d => {
          console.log('Response: ' + d);
        });
      });

      postReq.on('error', error => {
        console.log(error)
      });

      // Post the request with data
      postReq.write(postData);
      postReq.end();
    }
    res.end();
  }).listen(80);
}
main().catch(console.error);

HTTP/REST

يستخدم مثال بايثون هذا إطار عمل Flask ومكتبة الطلبات لتوضيح تدفق OAuth 2.0 على الويب. نوصي باستخدام مكتبة برامج Google API للغة بايثون في هذا المسار. (يستخدم المثال الوارد في علامة التبويب Python مكتبة البرامج).

import json

import flask
import requests


app = flask.Flask(__name__)

CLIENT_ID = '123456789.apps.googleusercontent.com'
CLIENT_SECRET = 'abc123'  # Read from a file or environmental variable in a real app
SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly'
REDIRECT_URI = 'http://example.com/oauth2callback'


@app.route('/')
def index():
  if 'credentials' not in flask.session:
    return flask.redirect(flask.url_for('oauth2callback'))
  credentials = json.loads(flask.session['credentials'])
  if credentials['expires_in'] <= 0:
    return flask.redirect(flask.url_for('oauth2callback'))
  else:
    headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])}
    req_uri = 'https://www.googleapis.com/drive/v2/files'
    r = requests.get(req_uri, headers=headers)
    return r.text


@app.route('/oauth2callback')
def oauth2callback():
  if 'code' not in flask.request.args:
    auth_uri = ('https://accounts.google.com/o/oauth2/v2/auth?response_type=code'
                '&client_id={}&redirect_uri={}&scope={}').format(CLIENT_ID, REDIRECT_URI, SCOPE)
    return flask.redirect(auth_uri)
  else:
    auth_code = flask.request.args.get('code')
    data = {'code': auth_code,
            'client_id': CLIENT_ID,
            'client_secret': CLIENT_SECRET,
            'redirect_uri': REDIRECT_URI,
            'grant_type': 'authorization_code'}
    r = requests.post('https://oauth2.googleapis.com/token', data=data)
    flask.session['credentials'] = r.text
    return flask.redirect(flask.url_for('index'))


if __name__ == '__main__':
  import uuid
  app.secret_key = str(uuid.uuid4())
  app.debug = False
  app.run()

قواعد التحقق من معرِّف الموارد المنتظم (URI) لإعادة التوجيه

تطبّق Google قواعد التحقق التالية لإعادة توجيه معرّفات الموارد المنتظمة (URI) لمساعدة المطوّرين في الحفاظ على أمان تطبيقاتهم. يجب أن تتقيّد معرّفات الموارد المنتظمة (URI) لإعادة التوجيه بهذه القواعد. راجِع القسم 3 من RFC 3986 للتعرّف على تعريف النطاق والمضيف والمسار وطلب البحث والمخطط ومعلومات المستخدم المذكورة أدناه.

قواعد التحقّق
المخطط

يجب أن تستخدم معرّفات الموارد المنتظمة (URI) لإعادة التوجيه مخطط HTTPS، وليس HTTP عاديًا. يتم استثناء معرّفات الموارد المنتظمة (URI) للمضيف المحلي (بما في ذلك معرّفات الموارد المنتظمة (URI) لعناوين IP للمضيف المحلي) من هذه القاعدة.

المضيف

لا يمكن أن تكون المضيفات عناوين IP أولية. يتم استثناء عناوين IP للمضيف المحلي من هذه القاعدة.

النطاق
  • يجب أن تنتمي نطاقات المستوى الأعلى للمضيف (نطاقات المستوى الأعلى) إلى قائمة اللاحقات العلنية.
  • لا يمكن أن تكون النطاقات المضيفة “googleusercontent.com”.
  • لا يمكن أن تحتوي معرّفات الموارد المنتظمة (URI) لإعادة التوجيه على نطاقات لتقصير عناوين URL (مثل goo.gl) ما لم يكن التطبيق يملك النطاق. بالإضافة إلى ذلك، إذا اختار تطبيق يمتلك نطاق تقصير إعادة التوجيه إلى ذلك النطاق، يجب أن يحتوي معرّف الموارد المنتظم (URI) هذا لإعادة التوجيه على “/google-callback/” في مساره أو أن ينتهي بـ “/google-callback”.
  • معلومات المستخدِم

    لا يمكن أن تحتوي معرّفات الموارد المنتظمة (URI) لإعادة التوجيه على المكوِّن الفرعي لمعلومات المستخدم.

    المسار

    لا يمكن أن تحتوي معرّفات الموارد المنتظمة (URI) لإعادة التوجيه على مسح مسار (يُعرف أيضًا باسم "تتبع تراجع الدليل")، والذي يتم تمثيله بترميز “/..” أو “\..” أو ترميز عناوين URL الخاصة بهما.

    طلب بحث

    لا يمكن أن تتضمّن معرّفات الموارد المنتظمة (URI) لإعادة التوجيه عمليات إعادة توجيه مفتوحة.

    جزء

    لا يمكن أن تحتوي معرّفات الموارد المنتظمة (URI) لإعادة التوجيه على مكوِّن التجزئة.

    الأحرف لا يمكن أن تحتوي معرّفات الموارد المنتظمة (URI) لإعادة التوجيه على أحرف معيّنة، بما في ذلك:
    • أحرف البدل ('*')
    • أحرف ASCII غير قابلة للطباعة
    • ترميزات النسبة المئوية غير صالحة (أي ترميز للنسبة المئوية لا يتبع شكل ترميز عنوان URL لعلامة النسبة المئوية متبوعًا برقمَين سداسيَين عشريَين)
    • أحرف خالية (حرف فارغ مرمّز، على سبيل المثال %00، %C0%80)

    التفويض التزايدي

    في بروتوكول OAuth 2.0، يطلب تطبيقك إذنًا للوصول إلى الموارد التي يتم تحديدها من خلال النطاقات. يُعتبر طلب الحصول على إذن للموارد في الوقت الذي تحتاج فيه إلى تجربة المستخدم من أفضل الممارسات المتعلقة بتجربة المستخدم. ولتفعيل هذه الممارسة، يتيح خادم التفويض من Google التفويض المتزايد. تتيح لك هذه الميزة طلب النطاقات حسب الحاجة، وإذا منح المستخدم إذنًا للنطاق الجديد، تعرض رمز التفويض الذي قد يتم استبداله برمز مميز يحتوي على جميع النطاقات التي منحها المستخدم للمشروع.

    على سبيل المثال، قد يحتاج التطبيق الذي يتيح للمستخدمين عيّنات من المقاطع الموسيقية وإنشاء التشكيلات إلى عدد قليل جدًا من الموارد في وقت تسجيل الدخول، وليس فقط اسم الشخص الذي يسجّل الدخول. مع ذلك، يتطلّب حفظ مزيج مكتمل الوصول إلى Google Drive. قد يجد معظم المستخدمين أنه من الطبيعي أن يطلب منهم الوصول إلى Google Drive فقط عندما يكون التطبيق بحاجة إليه.

    في هذه الحالة، قد يطلب التطبيق في وقت تسجيل الدخول نطاقَي openid وprofile لتنفيذ تسجيل الدخول الأساسي، ثم يطلب لاحقًا نطاق https://www.googleapis.com/auth/drive.file في وقت تقديم الطلب الأول لحفظ التشكيلة.

    لتنفيذ التفويض الإضافي، عليك إكمال المسار العادي لطلب رمز دخول، مع التأكّد من أنّ طلب التفويض يتضمّن النطاقات التي تم منحها سابقًا. ويسمح هذا الأسلوب لتطبيقك بتجنُّب إدارة رموز دخول متعددة.

    تنطبق القواعد التالية على رمز الدخول الذي تم الحصول عليه من تفويض متزايد:

    • يمكن استخدام الرمز المميّز للوصول إلى الموارد المقابلة لأي من النطاقات المضمّنة في التفويض المجمّع الجديد.
    • عند استخدام الرمز المميّز لإعادة التحميل للتفويض المجمّع للحصول على رمز الدخول، يمثّل رمز الدخول التفويض المجمّع ويمكن استخدامه لأي من قيم scope المضمّنة في الاستجابة.
    • ويشمل التفويض المُجمَّع جميع النطاقات التي منحها المستخدم لمشروع واجهة برمجة التطبيقات حتى إذا كانت المِنَح قد طُلِب من عملاء مختلفين. على سبيل المثال، إذا منح المستخدم إذن الوصول إلى نطاق واحد باستخدام برنامج كمبيوتر سطح المكتب لتطبيق ما، ثم منح نطاقًا آخر للتطبيق نفسه من خلال برنامج للأجهزة الجوّالة، سيتضمّن التفويض المُجمَّع كلا النطاقين.
    • إذا إبطال رمز مميّز يمثّل تفويضًا مجمّعًا، سيتم إبطال إمكانية الوصول إلى جميع نطاقات هذا الإذن نيابةً عن المستخدم المرتبط في الوقت نفسه.

    تستخدم عيّنات التعليمات البرمجية الخاصة باللغة في الخطوة 1: ضبط معلَمات التفويض ونموذج عنوان URL لإعادة التوجيه HTTP/REST في الخطوة 2: إعادة التوجيه إلى خادم OAuth 2.0 من Google تستخدم جميعها تفويضًا متزايدًا. تعرض نماذج التعليمات البرمجية أدناه أيضًا الرمز الذي تحتاج إلى إضافته لاستخدام التفويض المتزايد.

    PHP

    $client->setIncludeGrantedScopes(true);

    Python

    في بايثون، اضبط وسيطة الكلمة الرئيسية include_granted_scopes على true للتأكد من أن طلب التفويض يتضمن نطاقات تم منحها سابقًا. من المحتمل جدًا ألا تكون include_granted_scopes هي وسيطة الكلمة الرئيسية الوحيدة التي تضبطها، كما هو موضّح في المثال أدناه.

    authorization_url, state = flow.authorization_url(
        # Enable offline access so that you can refresh an access token without
        # re-prompting the user for permission. Recommended for web server apps.
        access_type='offline',
        # Enable incremental authorization. Recommended as a best practice.
        include_granted_scopes='true')

    Ruby

    auth_client.update!(
      :additional_parameters => {"include_granted_scopes" => "true"}
    )

    Node.js

    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes: true
    });
    

    HTTP/REST

    GET https://accounts.google.com/o/oauth2/v2/auth?
      client_id=your_client_id&
      response_type=code&
      state=state_parameter_passthrough_value&
      scope=https%3A//www.googleapis.com/auth/drive.file&
      redirect_uri=https%3A//oauth2.example.com/code&
      prompt=consent&
      include_granted_scopes=true

    إعادة تحميل رمز الدخول (الوصول بلا إنترنت)

    تنتهي صلاحية رموز الدخول بشكل دوري وتصبح بيانات اعتماد غير صالحة لطلب ذي صلة من واجهة برمجة التطبيقات. يمكنك إعادة تحميل رمز الدخول بدون أن تطلب من المستخدم الإذن (حتى في حال عدم توفّر المستخدم) إذا طلبت الوصول بلا اتصال بالإنترنت إلى النطاقات المرتبطة بالرمز المميّز.

    • إذا كنت تستخدم مكتبة برامج Google API، يعمل كائن العميل على إعادة تحميل رمز الدخول حسب الحاجة ما دام يتم إعداد هذا الكائن للوصول بلا اتصال بالإنترنت.
    • إذا كنت لا تستخدم مكتبة برامج، عليك ضبط معلَمة طلب البحث HTTP access_type على offline عند إعادة توجيه المستخدم إلى خادم OAuth 2.0 من Google. في هذه الحالة، يعرض خادم تفويض Google رمز تحديث عند استبدال رمز تفويض برمز دخول. بعد ذلك، إذا انتهت صلاحية رمز الدخول (أو في أي وقت آخر)، يمكنك استخدام الرمز المميّز لإعادة التحميل للحصول على رمز دخول جديد.

    إنّ طلب الوصول بلا اتصال بالإنترنت هو من متطلبات أي تطبيق يحتاج إلى الوصول إلى Google API في حال عدم تواجد المستخدم. على سبيل المثال، التطبيق الذي يقدّم خدمات الاحتفاظ بنسخة احتياطية أو ينفّذ إجراءات في أوقات محدّدة مسبقًا يجب أن يكون قادرًا على إعادة تحميل رمز الدخول في حال عدم توفّر المستخدم. نمط الوصول التلقائي يسمى online.

    تحصل تطبيقات الويب من جهة الخادم والتطبيقات المثبّتة والأجهزة على رموز التحديث أثناء عملية التفويض. ولا تُستخدم رموز إعادة التحميل عادةً في تطبيقات الويب من جهة العميل (JavaScript).

    PHP

    إذا كان تطبيقك يحتاج إلى الوصول بلا اتصال بالإنترنت إلى واجهة برمجة تطبيقات Google، اضبط نوع وصول عميل واجهة برمجة التطبيقات على offline:

    $client->setAccessType("offline");

    بعد أن يمنح المستخدم إمكانية الوصول بلا اتصال بالإنترنت للنطاقات المطلوبة، يمكنك مواصلة استخدام عميل واجهة برمجة التطبيقات للوصول إلى Google APIs نيابةً عن المستخدم عندما يكون غير متصل بالإنترنت. سيُعيد كائن العميل إعادة تحميل رمز الدخول حسب الحاجة.

    Python

    في بايثون، اضبط وسيطة الكلمة الرئيسية access_type على offline لضمان قدرتك على إعادة تحميل رمز الدخول بدون الحاجة إلى طلب إذن من المستخدم مرة أخرى. من المحتمل جدًا ألا تكون access_type هي وسيطة الكلمة الرئيسية الوحيدة التي تضبطها، كما هو موضّح في المثال أدناه.

    authorization_url, state = flow.authorization_url(
        # Enable offline access so that you can refresh an access token without
        # re-prompting the user for permission. Recommended for web server apps.
        access_type='offline',
        # Enable incremental authorization. Recommended as a best practice.
        include_granted_scopes='true')

    بعد أن يمنح المستخدم إمكانية الوصول بلا اتصال بالإنترنت للنطاقات المطلوبة، يمكنك مواصلة استخدام عميل واجهة برمجة التطبيقات للوصول إلى Google APIs نيابةً عن المستخدم عندما يكون غير متصل بالإنترنت. سيُعيد كائن العميل إعادة تحميل رمز الدخول حسب الحاجة.

    Ruby

    إذا كان تطبيقك يحتاج إلى الوصول بلا اتصال بالإنترنت إلى واجهة برمجة تطبيقات Google، اضبط نوع وصول عميل واجهة برمجة التطبيقات على offline:

    auth_client.update!(
      :additional_parameters => {"access_type" => "offline"}
    )

    بعد أن يمنح المستخدم إمكانية الوصول بلا اتصال بالإنترنت للنطاقات المطلوبة، يمكنك مواصلة استخدام عميل واجهة برمجة التطبيقات للوصول إلى Google APIs نيابةً عن المستخدم عندما يكون غير متصل بالإنترنت. سيُعيد كائن العميل إعادة تحميل رمز الدخول حسب الحاجة.

    Node.js

    إذا كان تطبيقك يحتاج إلى الوصول بلا اتصال بالإنترنت إلى واجهة برمجة تطبيقات Google، اضبط نوع وصول عميل واجهة برمجة التطبيقات على offline:

    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes: true
    });
    

    بعد أن يمنح المستخدم إمكانية الوصول بلا اتصال بالإنترنت للنطاقات المطلوبة، يمكنك مواصلة استخدام عميل واجهة برمجة التطبيقات للوصول إلى Google APIs نيابةً عن المستخدم عندما يكون غير متصل بالإنترنت. سيُعيد كائن العميل إعادة تحميل رمز الدخول حسب الحاجة.

    تنتهي صلاحية رموز الدخول. ستستخدم هذه المكتبة تلقائيًا رمزًا مميّزًا لإعادة التحميل للحصول على رمز دخول جديد إذا كانت على وشك الانتهاء. لضمان تخزين أحدث الرموز المميّزة دائمًا، يمكنك بسهولة استخدام حدث الرموز المميّزة:

    oauth2Client.on('tokens', (tokens) => {
      if (tokens.refresh_token) {
        // store the refresh_token in your secure persistent database
        console.log(tokens.refresh_token);
      }
      console.log(tokens.access_token);
    });

    لا يحدث حدث الرموز المميّزة هذا إلا عند إجراء التفويض الأول، ويجب ضبط access_type على offline عند استدعاء طريقة generateAuthUrl لتلقّي الرمز المميّز لإعادة التحميل. إذا سبق لك أن منحت تطبيقك الأذونات المطلوبة بدون ضبط القيود المناسبة لتلقّي رمز مميّز لإعادة التحميل، ستحتاج إلى إعادة تفويض التطبيق لتلقّي رمز مميّز جديد للتحديث.

    لضبط refresh_token في وقت لاحق، يمكنك استخدام طريقة setCredentials:

    oauth2Client.setCredentials({
      refresh_token: `STORED_REFRESH_TOKEN`
    });
    

    بعد حصول العميل على رمز مميّز لإعادة التحميل، سيتم الحصول على رموز الدخول وإعادة تحميلها تلقائيًا في الطلب التالي لواجهة برمجة التطبيقات.

    HTTP/REST

    لإعادة تحميل رمز الدخول، يرسل تطبيقك طلب HTTPS POST إلى خادم تفويض Google (https://oauth2.googleapis.com/token) يتضمّن المَعلمات التالية:

    الحقول
    client_id رقم تعريف العميل الذي تم الحصول عليه من API Console.
    client_secret سر العميل الذي تم الحصول عليه من API Console.
    grant_type كما هو موضّح في مواصفات OAuth 2.0، يجب ضبط قيمة هذا الحقل على refresh_token.
    refresh_token الرمز المميّز لإعادة التحميل الذي يظهر من تبادل رمز التفويض.

    يعرض المقتطف التالي نموذجًا للطلب:

    POST /token HTTP/1.1
    Host: oauth2.googleapis.com
    Content-Type: application/x-www-form-urlencoded
    
    client_id=your_client_id&
    client_secret=your_client_secret&
    refresh_token=refresh_token&
    grant_type=refresh_token

    ما دام المستخدم لم إبطال إذن الوصول الممنوح للتطبيق، يعرض خادم الرمز المميّز كائن JSON يحتوي على رمز دخول جديد. يعرض المقتطف التالي نموذجًا للرد:

    {
      "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
      "expires_in": 3920,
      "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
      "token_type": "Bearer"
    }

    يُرجى العلم أنّ هناك حدودًا لعدد الرموز المميّزة لإعادة التحميل التي سيتم إصدارها، حيث يمكن ضبط حدّ أقصى واحد لكل مجموعة عميل/مستخدم، وحد آخر لكل مستخدم في جميع البرامج. يجب حفظ الرموز المميّزة لإعادة التحميل في مساحة التخزين طويلة الأجل ومواصلة استخدامها ما دامت صالحة. إذا كان تطبيقك يطلب عددًا كبيرًا جدًا من الرموز المميّزة لإعادة التحميل، قد يتخطّى هذه الحدود، وفي هذه الحالة ستتوقف الرموز المميّزة لإعادة التحميل القديمة عن العمل.

    إبطال رمز مميّز

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

    من الممكن أيضًا أن يلغي التطبيق إذن الوصول الممنوح له آليًا. وتُعدّ الإبطال الآلي أمرًا مهمًا في الحالات التي يلغي فيها المستخدم الاشتراك أو يزيل فيه تطبيقًا أو عندما تتغيّر موارد واجهة برمجة التطبيقات التي يتطلبها التطبيق بشكل كبير. وبعبارة أخرى، يمكن أن يتضمّن جزء من عملية الإزالة طلب بيانات من واجهة برمجة التطبيقات لضمان إزالة الأذونات التي تم منحها للتطبيق في السابق.

    PHP

    لإبطال رمز مميّز آليًا، يمكنك طلب الرمز البرمجي revokeToken():

    $client->revokeToken();

    Python

    لإبطال رمز مميّز آليًا، يمكنك إرسال طلب إلى https://oauth2.googleapis.com/revoke يتضمّن الرمز المميّز كمَعلمة ويحدّد عنوان Content-Type:

    requests.post('https://oauth2.googleapis.com/revoke',
        params={'token': credentials.token},
        headers = {'content-type': 'application/x-www-form-urlencoded'})

    Ruby

    لإبطال رمز مميّز آليًا، يمكنك إرسال طلب HTTP إلى نقطة النهاية oauth2.revoke:

    uri = URI('https://oauth2.googleapis.com/revoke')
    response = Net::HTTP.post_form(uri, 'token' => auth_client.access_token)
    

    ويمكن أن يكون الرمز المميّز بمثابة رمز الدخول أو رمز لإعادة التحميل. إذا كان الرمز المميّز عبارة عن رمز دخول ويحتوي على رمز مميّز مطابق لإعادة التحميل، سيتم أيضًا إبطال الرمز المميّز لإعادة التحميل.

    إذا تمت معالجة الإبطال بنجاح، يكون رمز حالة الردّ هو 200. بالنسبة إلى حالات الخطأ، يتم عرض رمز الحالة 400 مع رمز الخطأ.

    Node.js

    لإبطال رمز مميّز آليًا، يمكنك إرسال طلب HTTPS POST إلى نقطة نهاية /revoke:

    const https = require('https');
    
    // Build the string for the POST request
    let postData = "token=" + userCredential.access_token;
    
    // Options for POST request to Google's OAuth 2.0 server to revoke a token
    let postOptions = {
      host: 'oauth2.googleapis.com',
      port: '443',
      path: '/revoke',
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': Buffer.byteLength(postData)
      }
    };
    
    // Set up the request
    const postReq = https.request(postOptions, function (res) {
      res.setEncoding('utf8');
      res.on('data', d => {
        console.log('Response: ' + d);
      });
    });
    
    postReq.on('error', error => {
      console.log(error)
    });
    
    // Post the request with data
    postReq.write(postData);
    postReq.end();
    

    ويمكن أن تكون مَعلمة الرمز المميّز عبارة عن رمز دخول أو رمز مميّز لإعادة التحميل. إذا كان الرمز المميّز عبارة عن رمز دخول ويحتوي على رمز مميّز مطابق لإعادة التحميل، سيتم أيضًا إبطال الرمز المميّز لإعادة التحميل.

    إذا تمت معالجة الإبطال بنجاح، يكون رمز حالة الردّ هو 200. بالنسبة إلى حالات الخطأ، يتم عرض رمز الحالة 400 مع رمز الخطأ.

    HTTP/REST

    لإبطال رمز مميّز آليًا، يطلب تطبيقك إلى https://oauth2.googleapis.com/revoke يتضمّن الرمز المميّز كمَعلمة:

    curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
            https://oauth2.googleapis.com/revoke?token={token}

    ويمكن أن يكون الرمز المميّز بمثابة رمز الدخول أو رمز لإعادة التحميل. إذا كان الرمز المميّز عبارة عن رمز دخول وكان له رمز مميّز مطابق لإعادة التحميل، سيتم أيضًا إبطال الرمز المميّز لإعادة التحميل.

    إذا تمت معالجة الإبطال بنجاح، يكون رمز حالة HTTP للاستجابة هو 200. بالنسبة إلى حالات الخطأ، يتم عرض رمز حالة HTTP 400 مع رمز الخطأ.