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

(صغيرة) . لمزيد من المعلومات، راجِع نظرة عامة على المصادقة في مستندات Google Cloud Platform.

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

وعادةً ما يستخدم التطبيق حساب خدمة عندما يستخدم التطبيق Google APIs للعمل مع بياناته الخاصة بدلاً من بيانات المستخدم. على سبيل المثال، يستخدم أي تطبيق يستخدم Google Cloud Datastore للاحتفاظ بالبيانات حساب خدمة لمصادقة استدعاءاته لواجهة برمجة تطبيقات Google Cloud Datastore.

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

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

نظرة عامة

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

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

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

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

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

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

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

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

首先,创建一个服务帐户:

  1. 打开 Service accounts page
  2. If prompted, select a project, or create a new one.
  3. 单击创建服务帐户
  4. Service account details下,键入服务帐户的名称、ID 和描述,然后点击Create and continue
  5. 可选:在Grant this service account access to project下,选择要授予服务帐户的 IAM 角色。
  6. 单击继续
  7. 可选:在Grant users access to this service account下,添加允许使用和管理服务帐户的用户或组。
  8. 单击完成

接下来,创建一个服务帐户密钥:

  1. 单击您创建的服务帐户的电子邮件地址。
  2. 单击密钥选项卡。
  3. 添加密钥下拉列表中,选择创建新密钥
  4. 单击创建

您的新公钥/私钥对已生成并下载到您的机器上;它作为私钥的唯一副本。您有责任安全地存储它。如果您丢失了这个密钥对,您将需要生成一个新的。

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

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

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

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

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

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

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

جارٍ التحضير لإجراء استدعاء معتمد لواجهة برمجة التطبيقات

لغة Java

بعد الحصول على عنوان البريد الإلكتروني للعميل والمفتاح الخاص من API Console، استخدِم مكتبة برامج "Google APIs" للغة جافا لإنشاء كائن GoogleCredential من بيانات اعتماد حساب الخدمة والنطاقات التي يحتاج تطبيقك إلى الوصول إليها. مثلاً:

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.sqladmin.SQLAdminScopes;

// ...

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN));

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

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

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

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN))
    .createDelegated("user@example.com");

استخدم الكائن GoogleCredential لاستدعاء واجهات برمجة تطبيقات Google في تطبيقك.

لغة Python

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

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

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

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

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

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

استخدم كائن بيانات الاعتماد لاستدعاء واجهات برمجة تطبيقات Google في تطبيقك.

HTTP/REST

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

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

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

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

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

يستخدم تطبيق الخادم JWT لطلب رمز مميز من خادم تفويض Google، ثم يستخدم الرمز المميز لطلب نقطة نهاية واجهة برمجة تطبيقات Google. لا يوجد مستخدم نهائي.

تصف بقية هذا القسم تفاصيل إنشاء JWT، وتوقيع 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

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

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

{"alg":"RS256","typ":"JWT"}

يتم تمثيل Base64url على النحو التالي:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
تشكيل مجموعة مطالبات 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 بالتوقيت العالمي المنسق، 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 الموقّع، يمكن للتطبيق استخدامه لطلب رمز الدخول. طلب رمز الدخول هذا هو طلب HTTPS POST، والنص الأساسي مشفر بعنوان URL. يظهر عنوان 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.

استدعاء واجهات Google APIs

لغة Java

استخدِم الكائن GoogleCredential لاستدعاء واجهات برمجة تطبيقات Google من خلال إكمال الخطوات التالية:

  1. أنشئ كائن خدمة لواجهة برمجة التطبيقات التي تريد استدعاؤها باستخدام الكائن GoogleCredential. على سبيل المثال:
    SQLAdmin sqladmin =
        new SQLAdmin.Builder(httpTransport, JSON_FACTORY, credential).build();
  2. تقديم طلبات إلى خدمة واجهة برمجة التطبيقات باستخدام الواجهة التي يوفِّرها كائن الخدمة. على سبيل المثال، لإدراج مثيلات قواعد بيانات Cloud SQL في مشروع example-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 في مشروع example-example-123:
    response = sqladmin.instances().list(project='exciting-example-123').execute()

HTTP/REST

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

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

أمثلة HTTP GET

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

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. تم تفويض حساب الخدمة باستخدام عنوان البريد الإلكتروني للعميل بدلاً من معرِّف العميل (رقمي) في وحدة تحكم المشرف. في صفحة التفويض على مستوى النطاق في وحدة تحكم المشرف، أزِل البرنامج وأعِد إضافته باستخدام المعرّف الرقمي.
access_denied (أي قيمة) إذا كنت تستخدم التفويض على مستوى النطاق، لن يتم تفويض نطاق واحد أو أكثر من النطاقات المطلوبة في وحدة تحكم المشرف.

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

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

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

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

invalid_client (أي قيمة)

برنامج OAuth أو رمز JWT المميز غير صالح أو تمت تهيئته بصورة غير صحيحة.

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

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

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

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

invalid_grant Not a valid email. المستخدم غير موجود. تحقَّق من صحة عنوان البريد الإلكتروني في المطالبة (حقل) 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، وضمن إدارة الهوية وإمكانية الوصول (IAM) والمشرف > حسابات الخدمة، فعِّل حساب الخدمة الذي يحتوي على "رقم تعريف المفتاح" المُستخدَم لتوقيع التأكيد.

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

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

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

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

إذا كانت واجهة برمجة التطبيقات التي تريد استدعاؤها تتضمن تعريف خدمة منشورًا في مستودع GitHub ضمن Google APIs، يمكنك إجراء طلبات بيانات من واجهة برمجة التطبيقات المفوَّضة باستخدام 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، حدِّد وقت Unix الحالي، وبالنسبة إلى الحقل exp، حدِّد الوقت بعد 3600 ثانية بالضبط عندما تنتهي صلاحية JWT.

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

مثلاً:

لغة Java

باستخدام google-api-java-client وjava-jwt:

GoogleCredential credential =
        GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"));
PrivateKey privateKey = credential.getServiceAccountPrivateKey();
String privateKeyId = credential.getServiceAccountPrivateKeyId();

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