OAuth 2.0 لتطبيقات الويب من جهة العميل

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

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

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

مكتبة برامج Google APIs وGoogle Identity Services

إذا كنت تستخدم مكتبة برامج Google APIs لتطبيقات JavaScript لإجراء طلبات مفوَّضة إلى Google، عليك استخدام مكتبة JavaScript في Google Identity Services لمعالجة مسار OAuth 2.0. يُرجى الاطّلاع على نموذج الرموز المميّزة في خدمات Google لتحديد الهوية، والذي يستند إلى مسار منح الإذن الضمني في OAuth 2.0.

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

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

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

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

  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. أكمل النموذج. التطبيقات التي تستخدم JavaScript لتقديم طلبات مصرَّح بها من Google API يجب أن تحدّد مصادر JavaScript المصرَّح بها. تحدِّد المصادر النطاقات التي يمكن لتطبيقك إرسال طلبات إليها على خادم OAuth 2.0. ويجب أن تلتزم هذه المصادر بقواعد التحقّق من Google.

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

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

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

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

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

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

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

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

نقاط نهاية OAuth 2.0

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

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

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

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

redirect_uri مطلوب

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

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

response_type مطلوب

يجب أن تضبط تطبيقات JavaScript قيمة المَعلمة على token. تُوجّه هذه القيمة "خادم تفويض Google" لإرجاع رمز الوصول كزوج name=value في معرّف المقتطف لعنوان URL (#) الذي تتم إعادة توجيه المستخدم إليه بعد إكمال عملية التفويض.

scope مطلوب

قائمة مفصولة بالفواصل بالنطاقات التي تحدِّد الموارد التي يمكن لتطبيقك الوصول إليها نيابةً عن المستخدم وتُستخدَم هذه القيم لعرض شاشة الموافقة التي تعرِضها 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 اطلب من المستخدم اختيار حساب.

نموذج إعادة توجيه إلى خادم التفويض في Google

يظهر أدناه مثال على عنوان URL، مع فواصل أسطر ومسافات لتسهيل القراءة.

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

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

رمز JavaScript النموذجي

يوضِّح المقتطف التالي من JavaScript كيفية بدء عملية التفويض في JavaScript بدون استخدام مكتبة Google APIs Client Library لـ JavaScript. بما أنّ نقطة نهاية OAuth 2.0 هذه لا تتيح مشاركة الموارد المتعدّدة المصادر (CORS)، ينشئ المقتطف نموذجًا يفتح الطلب إلى نقطة النهاية هذه.

/*
 * Create form to request access token from Google's OAuth 2.0 server.
 */
function oauthSignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';

  // Create <form> element to submit parameters to OAuth 2.0 endpoint.
  var form = document.createElement('form');
  form.setAttribute('method', 'GET'); // Send as a GET request.
  form.setAttribute('action', oauth2Endpoint);

  // Parameters to pass to OAuth 2.0 endpoint.
  var params = {'client_id': 'YOUR_CLIENT_ID',
                'redirect_uri': 'YOUR_REDIRECT_URI',
                'response_type': 'token',
                'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly',
                'include_granted_scopes': 'true',
                'state': 'pass-through value'};

  // Add form parameters as hidden input values.
  for (var p in params) {
    var input = document.createElement('input');
    input.setAttribute('type', 'hidden');
    input.setAttribute('name', p);
    input.setAttribute('value', params[p]);
    form.appendChild(input);
  }

  // Add form to page and submit it to open the OAuth 2.0 endpoint.
  document.body.appendChild(form);
  form.submit();
}

الخطوة 2: تطلب 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 Sign-In لنظام التشغيل iOS أو AppAuth لنظام التشغيل iOS من OpenID Foundation.

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

org_internal

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

invalid_client

المصدر الذي تم تقديم الطلب منه غير مصرّح به لهذا العميل. يُرجى الاطّلاع على origin_mismatch.

invalid_grant

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

origin_mismatch

قد لا يكون المخطّط و/أو النطاق و/أو المنفذ لبرنامج JavaScript الذي يُنشئ طلب التفويض مطابقًا لمعرّف الموارد المنتظم (URI) لمصدر JavaScript المسموح به والمسجّل لرقم تعريف عميل OAuth. راجِع مصادر JavaScript المعتمَدة في Google API Console Credentials page.

redirect_uri_mismatch

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

قد لا يكون المخطّط و/أو النطاق و/أو المنفذ لبرنامج JavaScript الذي يُنشئ طلب التفويض مطابقًا لمعرّف الموارد المنتظم (URI) لمصدر JavaScript المسموح به والمسجّل لرقم تعريف عميل OAuth. راجِع مصادر JavaScript المعتمَدة في Google API Console Credentials page.

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

invalid_request

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

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

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

نقاط نهاية OAuth 2.0

يُرسِل خادم OAuth 2.0 استجابة إلى redirect_uri المحدّد في طلب رمز الوصول.

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

  • استجابة رمز الدخول:

    https://oauth2.example.com/callback#access_token=4/P7q7W91&token_type=Bearer&expires_in=3600

    بالإضافة إلى المَعلمة access_token، تحتوي سلسلة المقتطف أيضًا على المَعلمة token_type التي يتم ضبطها دائمًا على Bearer، والمَعلمة expires_in التي تحدّد مدة صلاحية الرمز المميّز بالثواني. إذا تم تحديد المَعلمة state في طلب الرمز المميّز للوصول، يتم أيضًا تضمين قيمتها في الاستجابة.

  • استجابة خطأ:
    https://oauth2.example.com/callback#error=access_denied

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

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

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

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

الخطوة 4: التحقّق من النطاقات التي منحها المستخدمون

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

نقاط نهاية OAuth 2.0

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

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

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

استدعاء واجهات برمجة تطبيقات Google

نقاط نهاية OAuth 2.0

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

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

أمثلة على طلبات HTTP GET

قد يبدو طلب البيانات من نقطة نهاية drive.files (Drive Files API) باستخدام عنوان 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

رمز JavaScript النموذجي

يوضّح مقتطف الرمز البرمجي أدناه كيفية استخدام مشاركة الموارد المتعددة المصادر (CORS) لإرسال طلب إلى Google API. لا يستخدم هذا المثال "مكتبة برامج Google APIs" لبرنامج JavaScript. ومع ذلك، حتى إذا لم تكن تستخدِم مكتبة العميل، من المرجّح أن يساعدك دليل إتاحة بروتوكول مشاركة الموارد المشتركة المنشأ (CORS) في مستندات هذه المكتبة على فهم هذه الطلبات بشكل أفضل.

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

var xhr = new XMLHttpRequest();
xhr.open('GET',
    'https://www.googleapis.com/drive/v3/about?fields=user&' +
    'access_token=' + params['access_token']);
xhr.onreadystatechange = function (e) {
  console.log(xhr.response);
};
xhr.send(null);

مثال كامل

نقاط نهاية OAuth 2.0

يوضّح نموذج الرمز البرمجي هذا كيفية إكمال عملية OAuth 2.0 في JavaScript بدون استخدام مكتبة Google APIs Client Library لـ JavaScript. هذا الرمز مخصّص لصفحة HTML تعرِض زرًا لمحاولة إرسال طلب إلى واجهة برمجة التطبيقات. في حال النقر على الزر، يتحقّق الرمز من ما إذا كانت الصفحة قد حفظت رمز علامة مميّزة للوصول إلى واجهة برمجة التطبيقات في مساحة التخزين المؤقتة للمتصفّح. وفي حال كان الأمر كذلك، يتم تنفيذ طلب البيانات من واجهة برمجة التطبيقات. وبخلاف ذلك، يبدأ مسار OAuth 2.0.

بالنسبة إلى مسار OAuth 2.0، تتّبع الصفحة الخطوات التالية:

  1. ويوجّه المستخدم إلى خادم OAuth 2.0 من Google الذي يطلب الوصول إلى النطاقَين https://www.googleapis.com/auth/drive.metadata.readonly وhttps://www.googleapis.com/auth/calendar.readonly.
  2. بعد منح إذن الوصول (أو رفضه) إلى نطاق واحد أو أكثر من النطاقات المطلوبة، تتم إعادة توجيه المستخدم إلى الصفحة الأصلية التي تُحلِّل رمز الوصول من سلسلة معرّف المقتطف.
  3. تتحقّق الصفحة من النطاقات التي منحها المستخدم للوصول إلى التطبيق.
  4. إذا منح المستخدم إذن الوصول إلى النطاقات المطلوبة، تستخدم الصفحة رمز الدخول لتقديم طلب واجهة برمجة التطبيقات النموذجي.

    يُطلِب طلب واجهة برمجة التطبيقات طريقة about.get في Drive API لاسترداد معلومات عن حساب المستخدم المفوَّض على Google Drive.

  5. في حال تنفيذ الطلب بنجاح، يتم تسجيل ردّ واجهة برمجة التطبيقات في وحدة التحكّم في تصحيح أخطاء المتصفّح.

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

لتشغيل هذا الرمز على الجهاز، عليك ضبط قيم للمتغيّرين YOUR_CLIENT_ID و YOUR_REDIRECT_URI تتوافق مع بيانات اعتماد التفويض. يجب ضبط المتغيّر YOUR_REDIRECT_URI على عنوان URL نفسه الذي يتم عرض الصفحة عليه. يجب أن تتطابق القيمة تمامًا مع أحد عناوين URL المعتمَدة لإعادة التوجيه لعميل OAuth 2.0، والذي أعددته في API Console Credentials page. إذا كانت هذه القيمة لا تتطابق مع عنوان URL مفوَّض، ستظهر لك رسالة خطأ redirect_uri_mismatch. يجب أيضًا أن يكون قد تم تفعيل واجهة برمجة التطبيقات المناسبة لهذا الطلب في مشروعك.

<html><head></head><body>
<script>
  var YOUR_CLIENT_ID = 'REPLACE_THIS_VALUE';
  var YOUR_REDIRECT_URI = 'REPLACE_THIS_VALUE';

  // Parse query string to see if page request is coming from OAuth 2.0 server.
  var fragmentString = location.hash.substring(1);
  var params = {};
  var regex = /([^&=]+)=([^&]*)/g, m;
  while (m = regex.exec(fragmentString)) {
    params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
  }
  if (Object.keys(params).length > 0 && params['state']) {
    if (params['state'] == localStorage.getItem('state')) {
      localStorage.setItem('oauth2-test-params', JSON.stringify(params) );

      trySampleRequest();
    } else {
      console.log('State mismatch. Possible CSRF attack');
    }
  }

  // Function to generate a random state value
  function generateCryptoRandomState() {
    const randomValues = new Uint32Array(2);
    window.crypto.getRandomValues(randomValues);

    // Encode as UTF-8
    const utf8Encoder = new TextEncoder();
    const utf8Array = utf8Encoder.encode(
      String.fromCharCode.apply(null, randomValues)
    );

    // Base64 encode the UTF-8 data
    return btoa(String.fromCharCode.apply(null, utf8Array))
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '');
  }

  // If there's an access token, try an API request.
  // Otherwise, start OAuth 2.0 flow.
  function trySampleRequest() {
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    if (params && params['access_token']) { 
      // User authorized the request. Now, check which scopes were granted.
      if (params['scope'].includes('https://www.googleapis.com/auth/drive.metadata.readonly')) {
        // User authorized read-only Drive activity permission.
        // Calling the APIs, etc.
        var xhr = new XMLHttpRequest();
        xhr.open('GET',
          'https://www.googleapis.com/drive/v3/about?fields=user&' +
          'access_token=' + params['access_token']);
        xhr.onreadystatechange = function (e) {
          if (xhr.readyState === 4 && xhr.status === 200) {
            console.log(xhr.response);
          } else if (xhr.readyState === 4 && xhr.status === 401) {
            // Token invalid, so prompt for user permission.
            oauth2SignIn();
          }
        };
        xhr.send(null);
      }
      else {
        // User didn't authorize read-only Drive activity permission.
        // Update UX and application accordingly
        console.log('User did not authorize read-only Drive activity permission.');
      }

      // Check if user authorized Calendar read permission.
      if (params['scope'].includes('https://www.googleapis.com/auth/calendar.readonly')) {
        // User authorized Calendar read permission.
        // Calling the APIs, etc.
        console.log('User authorized Calendar read permission.');
      }
      else {
        // User didn't authorize Calendar read permission.
        // Update UX and application accordingly
        console.log('User did not authorize Calendar read permission.');
      } 
    } else {
      oauth2SignIn();
    }
  }

  /*
   * Create form to request access token from Google's OAuth 2.0 server.
   */
  function oauth2SignIn() {
    // create random state value and store in local storage
    var state = generateCryptoRandomState();
    localStorage.setItem('state', state);

    // Google's OAuth 2.0 endpoint for requesting an access token
    var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';

    // Create element to open OAuth 2.0 endpoint in new window.
    var form = document.createElement('form');
    form.setAttribute('method', 'GET'); // Send as a GET request.
    form.setAttribute('action', oauth2Endpoint);

    // Parameters to pass to OAuth 2.0 endpoint.
    var params = {'client_id': YOUR_CLIENT_ID,
                  'redirect_uri': YOUR_REDIRECT_URI,
                  'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly',
                  'state': state,
                  'include_granted_scopes': 'true',
                  'response_type': 'token'};

    // Add form parameters as hidden input values.
    for (var p in params) {
      var input = document.createElement('input');
      input.setAttribute('type', 'hidden');
      input.setAttribute('name', p);
      input.setAttribute('value', params[p]);
      form.appendChild(input);
    }

    // Add form to page and submit it to open the OAuth 2.0 endpoint.
    document.body.appendChild(form);
    form.submit();
  }
</script>

<button onclick="trySampleRequest();">Try sample request</button>
</body></html>

قواعد التحقّق من مصدر JavaScript

تطبّق Google قواعد التحقّق التالية على مصادر JavaScript للمساعدة في الحفاظ على أمان التطبيقات. يجب أن تلتزم مصادر JavaScript بهذه القواعد. يُرجى الاطّلاع على الفقرة 3 من RFC 3986 للاطّلاع على التعريفات الواردة أدناه للنطاق والمضيف والمخطّط.

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

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

المضيف

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

النطاق
  • يجب أن تنتمي نطاقات المستوى الأعلى للمضيف (نطاقات المستوى الأعلى) إلى قائمة اللاحقات العلنية.
  • لا يمكن أن تكون النطاقات المضيفة “googleusercontent.com”.
  • لا يمكن أن تحتوي مصادر JavaScript على نطاقات تقصير عناوين URL (مثل goo.gl) ما لم يكن التطبيق يملك النطاق.
  • Userinfo

    لا يمكن أن تحتوي مصادر JavaScript على المكوّن الفرعي userinfo.

    المسار

    لا يمكن أن تحتوي مصادر JavaScript على مكوّن المسار.

    طلب بحث

    لا يمكن أن تحتوي مصادر JavaScript على مكوّن الطلب.

    المقاطع

    لا يمكن أن تحتوي مصادر JavaScript على مكوّن القطعة.

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

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

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

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

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

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

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

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

    نقاط نهاية OAuth 2.0

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

    يوضّح مقتطف الرمز البرمجي التالي كيفية إجراء ذلك. يفترض المقتطف أنّك قد حفظت النطاقات التي يكون فيها معرّف المرور صالحًا في مساحة التخزين المحلية للمتصفّح. (يخزِّن المثال الكامل قائمة بالنطاقات التي يكون فيها رمز المرور صالحًا من خلال ضبط السمة oauth2-test-params.scope في مساحة التخزين المحلية للمتصفّح).

    تقارن المقتطف النطاقات التي يكون فيها رمز الوصول صالحًا بالنطاق الذي تريد استخدامه لطلب بحث معيّن. إذا لم يشمل رمز الوصول هذا النطاق، تبدأ عملية OAuth 2.0. هنا، تكون الدالة oauth2SignIn هي نفسها الدالة التي تم تقديمها في الخطوة 2 (والتي يتم تقديمها لاحقًا في مثال كامل).

    var SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly';
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    
    var current_scope_granted = false;
    if (params.hasOwnProperty('scope')) {
      var scopes = params['scope'].split(' ');
      for (var s = 0; s < scopes.length; s++) {
        if (SCOPE == scopes[s]) {
          current_scope_granted = true;
        }
      }
    }
    
    if (!current_scope_granted) {
      oauth2SignIn(); // This function is defined elsewhere in this document.
    } else {
      // Since you already have access, you can proceed with the API request.
    }

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

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

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

    نقاط نهاية OAuth 2.0

    لإبطال رمز مميّز آليًا، يُرسِل تطبيقك طلبًا إلى 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 مع رمز خطأ.

    يوضِّح المقتطف التالي من JavaScript كيفية إبطال رمز مميّز في JavaScript بدون استخدام مكتبة Google APIs Client Library لـ JavaScript. بما أنّ نقطة نهاية OAuth 2.0 من Google لإبطال الرموز المميزة لا تتوافق مع سياسة مشاركة الموارد المتعدّدة المصادر (CORS)، ينشئ الرمز نموذجًا ويُرسِل النموذج إلى نقطة النهاية بدلاً من استخدام طريقة XMLHttpRequest() لنشر الطلب.

    function revokeAccess(accessToken) {
      // Google's OAuth 2.0 endpoint for revoking access tokens.
      var revokeTokenEndpoint = 'https://oauth2.googleapis.com/revoke';
    
      // Create <form> element to use to POST data to the OAuth 2.0 endpoint.
      var form = document.createElement('form');
      form.setAttribute('method', 'post');
      form.setAttribute('action', revokeTokenEndpoint);
    
      // Add access token to the form so it is set as value of 'token' parameter.
      // This corresponds to the sample curl request, where the URL is:
      //      https://oauth2.googleapis.com/revoke?token={token}
      var tokenField = document.createElement('input');
      tokenField.setAttribute('type', 'hidden');
      tokenField.setAttribute('name', 'token');
      tokenField.setAttribute('value', accessToken);
      form.appendChild(tokenField);
    
      // Add form to page and submit it to actually revoke the token.
      document.body.appendChild(form);
      form.submit();
    }

    تنفيذ ميزة "الحماية العابرة للحساب"

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

    في ما يلي بعض الأمثلة على أنواع الأحداث التي ترسلها خدمة "الحماية بين الحسابات" من Google إلى تطبيقك:

    • https://schemas.openid.net/secevent/risc/event-type/sessions-revoked
    • https://schemas.openid.net/secevent/oauth/event-type/token-revoked
    • https://schemas.openid.net/secevent/risc/event-type/account-disabled

    اطّلِع على صفحة "حماية حسابات المستخدمين من خلال ميزة "الحماية العابرة للحساب" للحصول على مزيد من المعلومات عن كيفية تنفيذ ميزة "الحماية العابرة للحساب" والاطّلاع على القائمة الكاملة للأحداث المتاحة.