استخدام نموذج الرمز المميز

تساعدك مكتبة JavaScript google.accounts.oauth2 في إرسال طلب إلى المستخدم الموافقة والحصول على رمز دخول للعمل باستخدام بيانات المستخدمين. وهي تستند إلى مسار المنح الضمني في OAuth 2.0 وتم تصميمه للسماح لك بالاتصال بـ Google مباشرة باستخدام REST وCORS أو لاستخدام مكتبة برامج Google APIs جافا سكريبت (المعروفة أيضًا باسم gapi.client) لتوفير وصول بسيط ومرن إلى من واجهات برمجة تطبيقات أكثر تعقيدًا.

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

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

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

ضبط إعدادات الجهاز

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

إعداد عميل رمز مميّز

يمكنك الاتصال بالرقم initTokenClient() لإعداد برنامج رمز مميّز جديد باستخدام تطبيق الويب معرِّف العميل، يمكنك اختياريًا تضمين قائمة بواحد أو أكثر من النطاقات التي يستخدمها المستخدم يحتاج إلى الوصول إلى:

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  callback: (response) => {
    ...
  },
});

بدء مسار الرمز المميّز لـ OAuth 2.0

استخدِم الطريقة requestAccessToken() لتفعيل مسار تجربة المستخدم للرمز المميّز والحصول على . تطلب Google من المستخدم إجراء ما يلي:

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

تؤدي إيماءة مستخدم إلى ظهور مسار الرمز المميّز: <button onclick="client.requestAccessToken();">Authorize me</button>

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

يمكن للمستخدمين إغلاق محدِّد الحساب أو نوافذ تسجيل الدخول، وفي هذه الحالة فلن يتم استدعاء دالة الاستدعاء.

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

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

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

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

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

  • تطبيق Ajax من صفحة واحدة، ويستخدم غالبًا XMLHttpRequest مع إمكانية الوصول الديناميكي إلى الموارد.
  • يتم فصل العديد من صفحات الويب والموارد وإدارتها على أساس كل صفحة.

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

Ajax

يمكنك إضافة إمكانية منح الإذن المتزايد لتطبيقك من خلال إجراء مكالمات متعددة. إلى requestAccessToken() واستخدام قيمة الكائن OverridableTokenClientConfig scope لطلب نطاقات فردية في وقت الحاجة إليها عند الضرورة فقط. في هذا المثال، سيتم طلب الموارد وستكون مرئية فقط بعد أن تقوم إيماءة المستخدم بتوسيع قسم محتوى تم تصغيره.

تطبيق Ajax
إعداد عميل الرمز المميز عند تحميل الصفحة:
        const client = google.accounts.oauth2.initTokenClient({
          client_id: 'YOUR_GOOGLE_CLIENT_ID',
          callback: "onTokenResponse",
        });
      
طلب الموافقة والحصول على رموز الدخول من خلال إيماءات المستخدم انقر على `+` لفتح:

المستندات المطلوب قراءتها

عرض المستندات الأخيرة

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/documents.readonly'
             })
           );
        

الأحداث القادمة

عرض معلومات التقويم

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/calendar.readonly'
             })
           );
        

عرض الصور

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/photoslibrary.readonly'
             })
           );
        

كل طلب إلى requestAccessToken يؤدي إلى بدء لحظة موافقة المستخدم، وسيؤدي تطبيقك إلى يمكنهم الوصول فقط إلى الموارد التي يتطلبها القسم الذي يختار المستخدم وبالتالي تقييد مشاركة الموارد من خلال اختيار المستخدم.

صفحات ويب متعددة

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

تطبيق متعدّد الصفحات
صفحة ويب الرمز
الصفحة 1. المستندات للقراءة
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/documents.readonly',
  });
  client.requestAccessToken();
          
الصفحة 2. الفعاليات القادمة
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/calendar.readonly',
  });
  client.requestAccessToken();
          
الصفحة 3. لوحة عرض دوّارة للصور
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/photoslibrary.readonly',
  });
  client.requestAccessToken();
          

تطلب كل صفحة النطاق اللازم وتحصل على رمز دخول من خلال استدعاء initTokenClient() وrequestAccessToken() في وقت التحميل. في هذا السيناريو، استخدام صفحات الويب الفردية لفصل وظائف المستخدم والموارد حسب النطاق. في الواقع، قد تطلب صفحات فردية ونطاقات متعددة ذات صلة.

الأذونات الدقيقة

يتم التعامل مع الأذونات الدقيقة بالطريقة نفسها في جميع السيناريوهات. بعد يستدعي requestAccessToken() دالة معاودة الاتصال ورمز الدخول تحقق من أن المستخدم قد وافق على النطاقات المطلوبة باستخدام hasGrantedAllScopes() أو hasGrantedAnyScope(). على سبيل المثال:

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly \
          https://www.googleapis.com/auth/documents.readonly \
          https://www.googleapis.com/auth/photoslibrary.readonly',
  callback: (tokenResponse) => {
    if (tokenResponse && tokenResponse.access_token) {
      if (google.accounts.oauth2.hasGrantedAnyScope(tokenResponse,
          'https://www.googleapis.com/auth/photoslibrary.readonly')) {
        // Look at pictures
        ...
      }
      if (google.accounts.oauth2.hasGrantedAllScopes(tokenResponse,
          'https://www.googleapis.com/auth/calendar.readonly',
          'https://www.googleapis.com/auth/documents.readonly')) {
        // Meeting planning and review documents
        ...
      }
    }
  },
});

سيتم أيضًا احتساب أي مِنح سبق أن تم قبولها من جلسات أو طلبات سابقة. تضمينها في الرد. يتم الاحتفاظ بسجلّ موافقة المستخدم لكل مستخدم معرِّف العميل، ويستمر في المكالمات المتعددة إلى initTokenClient() أو requestAccessToken() بشكل تلقائي، لا تلزم موافقة المستخدم سوى أول الوقت الذي يزور فيه المستخدِم موقعك الإلكتروني ويطلب نطاقًا جديدًا، ولكن قد يُطلب منه ذلك كل تحميل صفحة باستخدام prompt=consent في عناصر إعداد برنامج Token Client.

التعامل مع الرموز المميزة

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

استخدام REST وCORS مع Google APIs

يمكن استخدام رمز الدخول لإجراء طلبات تمت مصادقتها إلى Google APIs باستخدام REST وCORS. يتيح هذا للمستخدمين إمكانية تسجيل الدخول ومنح الموافقة وإتاحة إصدار موقعك الإلكتروني ورمز الدخول للعمل باستخدام بيانات المستخدِم.

في هذا المثال، يمكنك عرض أحداث التقويم القادمة للمستخدمين الذين سجّلوا دخولهم باستخدام رمز الدخول الذي تم عرضه من قِبل tokenRequest():

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://www.googleapis.com/calendar/v3/calendars/primary/events');
xhr.setRequestHeader('Authorization', 'Bearer ' + tokenResponse.access_token);
xhr.send();

راجع كيفية استخدام سياسة مشاركة الموارد المتعددة المصادر (CORS) للوصول إلى واجهات Google APIs للتعرّف على مزيد من المعلومات.

يتناول القسم التالي كيفية الدمج بسهولة مع واجهات برمجة التطبيقات الأكثر تعقيدًا.

العمل مع مكتبة JavaScript لـ Google APIs

يعمل برنامج الرمز المميّز مع مكتبة برامج Google API للغة JavaScript. اطّلِع على مقتطف الرمز أدناه.

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  callback: (tokenResponse) => {
    if (tokenResponse && tokenResponse.access_token) {
      gapi.client.setApiKey('YOUR_API_KEY');
      gapi.client.load('calendar', 'v3', listUpcomingEvents);
    }
  },
});

function listUpcomingEvents() {
  gapi.client.calendar.events.list(...);
}

انتهاء صلاحية الرمز المميّز

حسب التصميم، فإن رموز الدخول لها فترة قصيرة. في حال انتهاء صلاحية رمز الدخول قبل انتهاء جلسة المستخدم، عليك الحصول على رمز مميّز جديد من خلال استدعاء requestAccessToken() من حدث يقوده المستخدم، مثل الضغط على زر.

عليك طلب الطريقة google.accounts.oauth2.revoke لإزالة موافقة المستخدم. الوصول إلى الموارد لجميع النطاقات الممنوحة لتطبيقك. إذن وصول صالح يجب إدخال رمز مميّز لإبطال هذا الإذن:

google.accounts.oauth2.revoke('414a76cb127a7ece7ee4bf287602ca2b56f8fcbf7fcecc2cd4e0509268120bd7', done => {
    console.log(done);
    console.log(done.successful);
    console.log(done.error);
    console.log(done.error_description);
  });