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

يتيح نظام Google OAuth 2.0 التفاعلات بين الخوادم، مثل التفاعلات بين تطبيق ويب وإحدى خدمات Google. في هذا السيناريو، تحتاج إلى حساب خدمة، وهو حساب يخص تطبيقك بدلاً من مستخدم نهائي فردي. يطلب تطبيقك من واجهات برمجة تطبيقات Google تنفيذ إجراءات بالنيابة عن حساب الخدمة، وبالتالي لا يشارك المستخدمون بشكل مباشر في هذه العملية. يُطلق على هذا السيناريو أحيانًا اسم "مصادقة OAUTH على مرحلتين" أو "2LO". (يشير المصطلح ذو الصلة "مصادقة OAUTH على ثلاث مراحل" إلى سيناريوهات يطلب فيها تطبيقك من Google APIs تنفيذ إجراءات بالنيابة عن المستخدمين النهائيين، وفيها تكون موافقة المستخدم مطلوبة في بعض الأحيان).

لمزيد من المعلومات، اطّلِع على أفضل الممارسات المتعلّقة بحسابات الخدمة.

عادةً، يستخدم التطبيق حساب خدمة عندما يستخدم واجهات Google API للعمل مع بياناته الخاصة بدلاً من بيانات المستخدم. على سبيل المثال، سيستخدم تطبيق يستعين بخدمة Google Cloud Datastore لتخزين البيانات بشكل دائم حساب خدمة للمصادقة على طلباته إلى واجهة برمجة التطبيقات Google Cloud Datastore API.

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

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

نظرة عامة

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

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

أخيرًا، يمكن لتطبيقك استخدام رمز الدخول لاستدعاء واجهات Google APIs.

إنشاء حساب خدمة

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

إذا كان تطبيقك يعمل على Google App Engine، يتم إعداد حساب خدمة تلقائيًا عند إنشاء مشروعك.

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

إذا كان تطبيقك لا يعمل على Google App Engine أو Google Compute Engine، عليك الحصول على بيانات الاعتماد هذه في Google API Console. لإنشاء بيانات اعتماد حساب الخدمة أو لعرض بيانات الاعتماد العامة التي سبق أن أنشأتها، اتّبِع الخطوات التالية:

أولاً، أنشئ حساب خدمة:

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

بعد ذلك، أنشئ مفتاح حساب خدمة:

  1. انقر على عنوان البريد الإلكتروني لحساب الخدمة الذي أنشأته.
  2. انقر على علامة التبويب المفاتيح.
  3. في القائمة المنسدلة إضافة مفتاح، اختَر إنشاء مفتاح جديد.
  4. انقر على إنشاء.

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

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

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

تفويض حساب الخدمة على مستوى النطاق

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

لتفويض صلاحية على مستوى النطاق إلى حساب خدمة، على المشرف المتميّز لنطاق Google Workspace إكمال الخطوات التالية:

  1. من وحدة تحكّم المشرف لنطاق Google Workspace، انتقِل إلى القائمة الرئيسية > الأمان > التحكّم في البيانات والوصول > عناصر تحكّم واجهة برمجة التطبيقات.
  2. في لوحة التفويض على مستوى النطاق، انقر على إدارة التفويض على مستوى النطاق.
  3. انقر على إضافة نطاق جديد.
  4. في حقل معرّف العميل، أدخِل معرّف العميل لحساب الخدمة. يمكنك العثور على معرّف العميل لحساب الخدمة في صفحة حسابات الخدمة.
  5. في الحقل نطاقات OAuth (مفصولة بفواصل)، أدخِل قائمة النطاقات التي يجب منح تطبيقك إذن الوصول إليها. على سبيل المثال، إذا كان تطبيقك يحتاج إلى إذن وصول كامل على مستوى النطاق إلى Google Drive API وواجهة برمجة تطبيقات "تقويم Google"، أدخِل: https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar.
  6. انقر على تفويض.

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

إجراء طلب بيانات من واجهة برمجة التطبيقات مفوَّض

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

جافا

بعد الحصول على عنوان البريد الإلكتروني للعميل والمفتاح الخاص من وحدة تحكّم واجهة برمجة التطبيقات، استخدِم مكتبة المصادقة من Google للغة Java لإنشاء عنصر GoogleCredentials من بيانات اعتماد حساب الخدمة ونطاقات الوصول التي يحتاجها تطبيقك. على سبيل المثال:

import com.google.auth.oauth2.GoogleCredentials;
import com.google.api.services.sqladmin.SQLAdminScopes;

// ...

GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream("ServiceAccountKey.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN));

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

تفويض السلطة على مستوى النطاق

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

GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream("ServiceAccountKey.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN))
    .createDelegated("workspace-user@example.com");

يُستخدَم العنصر GoogleCredentials لاستدعاء الإجراء createDelegated(). يجب أن تكون وسيطة طريقة createDelegated() مستخدمًا ينتمي إلى حسابك على Workspace. سيستخدم الرمز الذي يقدّم الطلب بيانات الاعتماد هذه لاستدعاء واجهات برمجة تطبيقات Google باستخدام حساب الخدمة.

Python

بعد الحصول على عنوان البريد الإلكتروني للعميل والمفتاح الخاص من API Console، استخدِم Google APIs Client Library for Python لإكمال الخطوات التالية:

  1. أنشِئ عنصر Credentials من بيانات اعتماد حساب الخدمة والنطاقات التي يحتاج تطبيقك إلى الوصول إليها. على سبيل المثال:
    from google.oauth2 import service_account
    
    SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin']
    SERVICE_ACCOUNT_FILE = '/path/to/ServiceAccountKey.json'
    
    credentials = service_account.Credentials.from_service_account_file(
            SERVICE_ACCOUNT_FILE, scopes=SCOPES)

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

  2. تفويض السلطة على مستوى النطاق

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

    delegated_credentials = credentials.with_subject('user@example.org')

استخدِم عنصر "بيانات الاعتماد" لطلب بيانات من Google APIs في تطبيقك.

HTTP/REST

بعد الحصول على معرّف العميل والمفتاح الخاص من API Console، يجب أن يكمل تطبيقك الخطوات التالية:

  1. أنشئ رمز JSON مميّز للويب (JWT، ويُلفظ "جوت") يتضمّن عنوانًا ومجموعة طلبات وتوقيعًا.
  2. اطلب رمز دخول من خادم مصادقة Google OAuth 2.0.
  3. تعامَل مع استجابة JSON التي يعرضها خادم التفويض.

توضّح الأقسام التالية كيفية إكمال هذه الخطوات.

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

عندما تنتهي صلاحية رمز الدخول، ينشئ تطبيقك رمز JWT آخر ويوقّعه ويطلب رمز دخول آخر.

يستخدم تطبيق الخادم رمز JWT لطلب رمز مميّز من خادم تفويض Google، ثم يستخدم الرمز المميز لطلب نقطة نهاية لواجهة Google API. لا يشارك أي مستخدم نهائي في هذه العملية.
الشكل 1. يستخدم تطبيق الخادم رمز JWT لطلب رمز مميّز من خادم تفويض Google، ثم يستخدم الرمز المميز لطلب نقطة نهاية لواجهة Google API. ولا يتطلّب ذلك أي تدخل من المستخدم النهائي.

يتناول الجزء المتبقي من هذا القسم تفاصيل إنشاء رمز JWT وتوقيعه وإنشاء طلب رمز الدخول والتعامل مع الردّ.

إنشاء رمز JWT

يتألف رمز JWT من ثلاثة أجزاء: العنوان ومجموعة المطالبات والتوقيع. العنوان ومجموعة المطالبات هما كائنان بتنسيق JSON. يتم تسلسل عناصر JSON هذه إلى وحدات بايت UTF-8، ثم يتم ترميزها باستخدام ترميز Base64url. توفّر عملية الترميز هذه مرونة ضد التغييرات في الترميز الناتجة عن عمليات الترميز المتكرّرة. يتم ربط العنوان ومجموعة المطالبات والتوقيع معًا باستخدام النقطة (.).

يتألف رمز JWT على النحو التالي:

{Base64url encoded header}.{Base64url encoded claim set}.{Base64url encoded signature}

سلسلة التوقيع الأساسية هي كما يلي:

{Base64url encoded header}.{Base64url encoded claim set}
إنشاء عنوان JWT

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

  • الخوارزمية إلزامية، ولها قيمة واحدة فقط: "alg": "RS256".
  • التنسيق إلزامي، ويتضمّن قيمة واحدة فقط: "typ": "JWT".
  • معرّف المفتاح اختياري، وهو معرّف مفتاح حساب الخدمة المستخدَم لتوقيع رمز JWT. في حال تحديد معرّف مفتاح غير صحيح، سيتم تجربة جميع المفاتيح المرتبطة بحساب الخدمة. في حال عدم العثور على مفتاح صالح، يتم رفض الرمز المميّز. تحتفظ Google بالحق في رفض الرموز المميزة التي تتضمّن معرّفات مفاتيح غير صحيحة.

تعتمد حسابات الخدمة على خوارزمية RSA SHA-256 وتنسيق الرمز المميز JWT. نتيجةً لذلك، يكون تمثيل JSON للعنوان على النحو التالي:

{"alg":"RS256","typ":"JWT", "kid":"370ab79b4513eb9bad7c9bd16a95cb76b5b2a56a"}

في ما يلي تمثيل Base64url لهذا الرمز:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsICJraWQiOiIzNzBhYjc5YjQ1MTNlYjliYWQ3YzliZDE2YTk1Y2I3NmI1YjJhNTZhIn0=
إنشاء مجموعة مطالبات JWT

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

المطالبات المطلوبة

يمكن أن تظهر المطالبات المطلوبة في مجموعة مطالبات JWT بأي ترتيب في مجموعة المطالبات.

الاسم الوصف
iss عنوان البريد الإلكتروني لحساب الخدمة
scope قائمة مفصولة بمسافات للأذونات التي يطلبها التطبيق.
aud تمثّل هذه السمة وصفًا للهدف المقصود من التأكيد. عند تقديم طلب للحصول على رمز دخول، تكون هذه القيمة دائمًا https://oauth2.googleapis.com/token.
exp وقت انتهاء صلاحية التأكيد، ويتم تحديده بالثواني منذ الساعة 00:00:00 بالتوقيت العالمي المنسق، في 1 يناير 1970. تبلغ مدة صلاحية هذه القيمة ساعة واحدة كحدّ أقصى بعد وقت الإصدار.
iat الوقت الذي تم فيه إصدار التأكيد، ويتم تحديده بالثواني منذ الساعة 00:00:00 بالتوقيت العالمي المنسق (UTC)، في 1 يناير 1970.

في ما يلي مثال على تمثيل JSON للحقول المطلوبة في مجموعة مطالبات JWT:

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "scope": "https://www.googleapis.com/auth/devstorage.read_only",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
المطالبات الإضافية

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

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

الاسم الوصف
sub تمثّل هذه السمة عنوان البريد الإلكتروني للمستخدم الذي يطلب التطبيق تفويض الوصول إليه.

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

في ما يلي مثال على مجموعة طلبات JWT تتضمّن الحقل sub:

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "sub": "some.user@example.com",
  "scope": "https://www.googleapis.com/auth/prediction",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
ترميز مجموعة المطالبات في رمز JWT

مثل عنوان JWT، يجب تسلسل مجموعة مطالبات JWT إلى UTF-8 وترميزها باستخدام Base64url-safe. في ما يلي مثال على تمثيل JSON لمجموعة مطالبات JWT:

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "scope": "https://www.googleapis.com/auth/prediction",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
احتساب التوقيع

توقيع JSON على الويب (JWS) هو المواصفات التي توجّه آليات إنشاء التوقيع لرمز JWT. يكون الإدخال الخاص بالتوقيع هو مصفوفة البايتات الخاصة بالمحتوى التالي:

{Base64url encoded header}.{Base64url encoded claim set}

يجب استخدام خوارزمية التوقيع في عنوان JWT عند احتساب التوقيع. خوارزمية التوقيع الوحيدة التي يتيحها خادم تفويض Google OAuth 2.0 هي RSA باستخدام خوارزمية التجزئة SHA-256. يتم التعبير عن ذلك على النحو RS256 في الحقل alg في عنوان JWT.

وقِّع على تمثيل UTF-8 للإدخال باستخدام SHA256withRSA (المعروف أيضًا باسم RSASSA-PKCS1-V1_5-SIGN مع دالة التجزئة SHA-256) باستخدام المفتاح الخاص الذي تم الحصول عليه من Google API Console. ستكون المخرجات عبارة عن صفيف بايت.

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

{Base64url encoded header}.
{Base64url encoded claim set}.
{Base64url encoded signature}

في ما يلي مثال على رمز JWT قبل ترميز Base64url:

{"alg":"RS256","typ":"JWT"}.
{
"iss":"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/prediction",
"aud":"https://oauth2.googleapis.com/token",
"exp":1328554385,
"iat":1328550785
}.
[signature bytes]

في ما يلي مثال على رمز JWT تم توقيعه وهو جاهز للإرسال:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL29hdXRoMi92NC90b2tlbiIsImV4cCI6MTMyODU1NDM4NSwiaWF0IjoxMzI4NTUwNzg1fQ.UFUt59SUM2_AW4cRU8Y0BYVQsNTo4n7AFsNrqOpYiICDu37vVt-tw38UKzjmUKtcRsLLjrR3gFW3dNDMx_pL9DVjgVHDdYirtrCekUHOYoa1CMR66nxep5q5cBQ4y4u2kIgSvChCTc9pmLLNoIem-ruCecAJYgI9Ks7pTnW1gkOKs0x3YpiLpzplVHAkkHztaXiJdtpBcY1OXyo6jTQCa3Lk2Q3va1dPkh_d--GU2M5flgd8xNBPYw4vxyt0mP59XZlHMpztZt0soSgObf7G3GXArreF_6tpbFsS3z2t5zkEiHuWJXpzcYr5zWTRPDEHsejeBSG8EgpLDce2380ROQ

طلب رمز دخول

بعد إنشاء رمز JWT الموقَّع، يمكن لأحد التطبيقات استخدامه لطلب رمز دخول. طلب رمز الدخول هذا هو طلب POST عبر HTTPS، ويتم ترميز النص باستخدام عنوان URL. على سبيل المثال:

https://oauth2.googleapis.com/token

يجب تضمين المَعلمات التالية في طلب HTTPS POST:

الاسم الوصف
grant_type استخدِم السلسلة التالية، مع ترميز عنوان URL حسب الحاجة: urn:ietf:params:oauth:grant-type:jwt-bearer
assertion رمز JWT، بما في ذلك التوقيع

في ما يلي تفريغ أولي لطلب HTTPS POST المستخدَم في طلب رمز دخول:

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

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.ixOUGehweEVX_UKXv5BbbwVEdcz6AYS-6uQV6fGorGKrHf3LIJnyREw9evE-gs2bmMaQI5_UbabvI4k-mQE4kBqtmSpTzxYBL1TCd7Kv5nTZoUC1CmwmWCFqT9RE6D7XSgPUh_jF1qskLa2w0rxMSjwruNKbysgRNctZPln7cqQ

هذا هو الطلب نفسه، ولكن باستخدام curl:

curl -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.RZVpzWygMLuL-n3GwjW1_yhQhrqDacyvaXkuf8HcJl8EtXYjGjMaW5oiM5cgAaIorrqgYlp4DPF_GuncFqg9uDZrx7pMmCZ_yHfxhSCXru3gbXrZvAIicNQZMFxrEEn4REVuq7DjkTMyCMGCY1dpMa8aWfTQFt3Eh7smLchaZsU
' https://oauth2.googleapis.com/token

التعامل مع الردود

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

{
  "access_token": "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M",
  "scope": "https://www.googleapis.com/auth/prediction"
  "token_type": "Bearer",
  "expires_in": 3600
}

يمكن إعادة استخدام رموز الدخول المميزة خلال فترة المدة المحدّدة بواسطة قيمة expires_in.

اعتبار مهم بشأن الأمان: فهم انتحال الهوية

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

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

جافا

استخدِم العنصر GoogleCredentials لطلب بيانات من Google APIs باتّباع الخطوات التالية:

  1. أنشئ عنصر خدمة لواجهة برمجة التطبيقات التي تريد طلبها باستخدام العنصر GoogleCredentials. على سبيل المثال:
    SQLAdmin sqladmin =
        new SQLAdmin.Builder(httpTransport, JSON_FACTORY, credentials).build();
  2. إرسال طلبات إلى خدمة واجهة برمجة التطبيقات باستخدام الواجهة التي يوفّرها عنصر الخدمة على سبيل المثال، لإدراج مثيلات قواعد بيانات Cloud SQL في المشروع exciting-example-123، اتّبِع الخطوات التالية:
    SQLAdmin.Instances.List instances =
        sqladmin.instances().list("exciting-example-123").execute();

Python

استخدِم العنصر Credentials المفوَّض لاستدعاء Google APIs من خلال إكمال الخطوات التالية:

  1. أنشئ عنصر خدمة لواجهة برمجة التطبيقات التي تريد طلبها. يمكنك إنشاء عنصر خدمة من خلال استدعاء الدالة build مع اسم واجهة برمجة التطبيقات وإصدارها وعنصر Credentials المفوَّض. على سبيل المثال، لطلب بيانات من الإصدار 1beta3 من Cloud SQL Administration API، استخدِم ما يلي:
    import googleapiclient.discovery
    
    sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta3', credentials=credentials)
  2. إرسال طلبات إلى خدمة واجهة برمجة التطبيقات باستخدام الواجهة التي يوفّرها عنصر الخدمة على سبيل المثال، لإدراج مثيلات قواعد بيانات Cloud SQL في المشروع exciting-example-123، اتّبِع الخطوات التالية:
    response = sqladmin.instances().list(project='exciting-example-123').execute()

HTTP/REST

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

يمكنك تجربة جميع Google APIs والاطّلاع على نطاقاتها في مساحة بروتوكول 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

عند انتهاء صلاحية رموز الدخول

تنتهي صلاحية رموز الدخول التي يصدرها خادم المصادقة Google OAuth 2.0 بعد المدة التي توفّرها قيمة expires_in. عند انتهاء صلاحية رمز الدخول، يجب أن ينشئ التطبيق رمز JWT آخر ويوقّعه ويطلب رمز دخول آخر.

رموز خطأ JWT

error حقل error_description حقل المعنى كيفية الحل
unauthorized_client Unauthorized client or scope in request. إذا كنت تحاول استخدام التفويض على مستوى النطاق، يعني ذلك أنّ حساب الخدمة غير مفوَّض في "وحدة تحكّم المشرف" الخاصة بنطاق المستخدم.

تأكَّد من تفويض حساب الخدمة في صفحة التفويض على مستوى النطاق في "وحدة تحكّم المشرف" للمستخدم في مطالبة sub (الحقل).

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

unauthorized_client Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested. تم تفويض حساب خدمة باستخدام عنوان البريد الإلكتروني للعميل بدلاً من معرّف العميل (رقمي) في "وحدة تحكّم المشرف"، أو تم استخدام "مجموعة Google" للتفويض. في صفحة التفويض على مستوى النطاق في "وحدة تحكّم المشرف"، أزِل العميل وأعِد إضافته باستخدام رقم التعريف، أو أزِل "مجموعة Google" واستبدِلها بالخدمة الفردية أو حساب المستخدم.
access_denied (أي قيمة) إذا كنت تستخدم تفويضًا على مستوى النطاق، لم يتم تفويض نطاق واحد أو أكثر من النطاقات المطلوبة في "وحدة تحكّم المشرف".

تأكَّد من تفويض حساب الخدمة في صفحة التفويض على مستوى النطاق ضمن "وحدة تحكّم المشرف" للمستخدم في مطالبة sub (الحقل)، ومن أنّها تتضمّن جميع النطاقات التي تطلبها في مطالبة scope في رمز JWT.

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

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

admin_policy_enforced (أي قيمة) لا يمكن لحساب Google منح الإذن بنطاق واحد أو أكثر من النطاقات المطلوبة بسبب سياسات مشرف حسابات Google Workspace.

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

invalid_client (أي قيمة)

عميل OAuth أو رمز JWT غير صالح أو تم إعداده بشكلٍ غير صحيح.

يُرجى الرجوع إلى وصف الخطأ للحصول على التفاصيل.

تأكَّد من أنّ رمز JWT المميّز صالح ويتضمّن المطالبات الصحيحة.

تأكَّد من إعداد عميل OAuth وحساب الخدمة بشكلٍ صحيح ومن استخدام عنوان البريد الإلكتروني الصحيح.

تأكَّد من أنّ رمز JWT المميّز صحيح وتم إصداره لمعرّف العميل في الطلب.

deleted_client (أي قيمة)

تم حذف عميل OAuth المستخدَم لتقديم الطلب. يمكن أن تتم عملية الحذف يدويًا أو تلقائيًا في حال عدم استخدام العملاء . يمكن استعادة العملاء المحذوفين في غضون 30 يومًا من الحذف. مزيد من المعلومات

استخدِم معرّف عميل لا يزال نشطًا.

invalid_grant Not a valid email أو Invalid email or User ID. المستخدم غير موجود. تأكَّد من صحة عنوان البريد الإلكتروني في مطالبة sub (الحقل).
invalid_grant

Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your 'iat' and 'exp' values and use a clock with skew to account for clock differences between systems.

يعني ذلك عادةً أنّ وقت النظام المحلي غير صحيح. قد يحدث ذلك أيضًا إذا كانت قيمة exp أكبر من 65 دقيقة في المستقبل من قيمة iat، أو إذا كانت قيمة exp أقل من قيمة iat.

تأكَّد من صحة الساعة على النظام الذي يتم فيه إنشاء رمز JWT. عند اللزوم، يُرجى مزامنة الوقت مع Google NTP.

invalid_grant Invalid JWT Signature.

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

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

فكِّ ترميز مجموعة المطالبات في رمز JWT وتحقَّق من أنّ المفتاح الذي وقّع على التأكيد مرتبط بحساب الخدمة.

جرِّب استخدام مكتبة OAuth من Google للتأكّد من إنشاء رمز JWT المميّز بشكلٍ صحيح.

invalid_scope Invalid OAuth scope or ID token audience provided. لم يتم طلب أي نطاقات (قائمة نطاقات فارغة)، أو أنّ أحد النطاقات المطلوبة غير متوفّر (أي غير صالح).

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

يُرجى العِلم أنّه يجب الفصل بين نطاقات scope باستخدام مسافات وليس فواصل.

disabled_client The OAuth client was disabled. تم إيقاف المفتاح المستخدَم لتوقيع بيان JWT.

انتقِل إلى Google API Console، وضِمن إدارة الهوية وإمكانية الوصول > حسابات الخدمة، فعِّل حساب الخدمة الذي يحتوي على "معرّف المفتاح" المستخدَم لتوقيع التأكيد.

org_internal This client is restricted to users within its organization. إنّ رقم تعريف عميل OAuth في الطلب هو جزء من مشروع يحدّ من إمكانية الوصول إلى حسابات Google في مؤسسة Google Cloud معيّنة.

استخدِم حساب خدمة من المؤسسة للمصادقة. أكِّد إعدادات نوع المستخدم لتطبيق OAuth.

ملحق: تفويض حساب الخدمة بدون بروتوكول OAuth

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

إذا كانت واجهة برمجة التطبيقات التي تريد طلب بيانات منها تتضمّن تعريف خدمة منشورًا في مستودع Google APIs على GitHub، يمكنك إجراء طلبات بيانات معتمَدة من واجهة برمجة التطبيقات باستخدام رمز JWT بدلاً من رمز الدخول. ولإجراء ذلك، يُرجى اتّباع الخطوات التالية:

  1. إنشاء حساب خدمة احرص على الاحتفاظ بملف JSON الذي تحصل عليه عند إنشاء الحساب.
  2. باستخدام أي مكتبة JWT عادية، مثل تلك المتوفّرة على jwt.io، أنشئ رمز JWT يتضمّن عنوانًا وحمولة مثل المثال التالي:
    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "abcdef1234567890"
    }
    .
    {
      "iss": "123456-compute@developer.gserviceaccount.com",
      "sub": "123456-compute@developer.gserviceaccount.com",
      "aud": "https://firestore.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600
    }
    • بالنسبة إلى الحقل kid في العنوان، حدِّد معرّف المفتاح الخاص لحساب الخدمة. يمكنك العثور على هذه القيمة في الحقل private_key_id في ملف JSON الخاص بحساب الخدمة.
    • في الحقلَين iss وsub، حدِّد عنوان البريد الإلكتروني الخاص بحساب الخدمة. يمكنك العثور على هذه القيمة في الحقل client_email في ملف JSON الخاص بحساب الخدمة. تحدّد هذه القيمة العميل بشكلٍ فريد، وهي تعمل وظيفيًا كمعرّف العميل.
    • بالنسبة إلى الحقل aud، حدِّد نقطة نهاية واجهة برمجة التطبيقات. على سبيل المثال: https://SERVICE.googleapis.com/.
    • بالنسبة إلى الحقل iat، حدِّد وقت بداية حقبة يونكس الحالي، وبالنسبة إلى الحقل exp، حدِّد الوقت الذي سينتهي فيه صلاحية رمز JWT، أي بعد 3600 ثانية بالضبط.

وقِّع رمز JWT باستخدام RSA-256 والمفتاح الخاص المتوفّر في ملف JSON لحساب الخدمة.

على سبيل المثال:

جافا

استخدام google-auth-library-java و java-jwt:

import com.google.auth.oauth2.ServiceAccountCredentials;
...
GoogleCredentials credentials =
        GoogleCredentials.fromStream(new FileInputStream("MyProject-1234.json"));
PrivateKey privateKey = ((ServiceAccountCredentials) credentials).getPrivateKey();
String privateKeyId = ((ServiceAccountCredentials) credentials).getPrivateKeyId();

long now = System.currentTimeMillis();

try {
    Algorithm algorithm = Algorithm.RSA256(null, privateKey);
    String signedJwt = JWT.create()
        .withKeyId(privateKeyId)
        .withIssuer("123456-compute@developer.gserviceaccount.com")
        .withSubject("123456-compute@developer.gserviceaccount.com")
        .withAudience("https://firestore.googleapis.com/")
        .withIssuedAt(new Date(now))
        .withExpiresAt(new Date(now + 3600 * 1000L))
        .sign(algorithm);
} catch ...

Python

باستخدام PyJWT:

iat = time.time()
exp = iat + 3600
payload = {'iss': '123456-compute@developer.gserviceaccount.com',
           'sub': '123456-compute@developer.gserviceaccount.com',
           'aud': 'https://firestore.googleapis.com/',
           'iat': iat,
           'exp': exp}
additional_headers = {'kid': PRIVATE_KEY_ID_FROM_JSON}
signed_jwt = jwt.encode(payload, PRIVATE_KEY_FROM_JSON, headers=additional_headers,
                       algorithm='RS256')
  1. أرسِل طلبًا إلى واجهة برمجة التطبيقات باستخدام رمز JWT الموقَّع كرمز مميّز لحامل الإذن:
    GET /v1/projects/abc/databases/123/indexes HTTP/1.1
    Authorization: Bearer SIGNED_JWT
    Host: firestore.googleapis.com

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

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

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