تسجيل الدخول بحساب Google للتطبيقات من جهة الخادم

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

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

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

تنفيذ تدفق الرمز لمرة واحدة

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

يوضح نموذج التعليمات البرمجية التالي كيفية إجراء تدفق التعليمة البرمجية لمرة واحدة.

تتطلب مصادقة تسجيل الدخول بحساب Google باستخدام تدفق رمز لمرة واحدة ما يلي:

الخطوة 1: إنشاء معرِّف العميل وسر العميل

لإنشاء معرِّف العميل وسر العميل، أنشئ مشروعًا على وحدة تحكم واجهة برمجة تطبيقات Google، وأعدّ معرِّف عميل OAuth، وسجِّل مصادر JavaScript:

  1. انتقِل إلى وحدة التحكم في واجهة Google API.

  2. من القائمة المنسدلة للمشروع، اختَر مشروعًا حاليًا أو أنشئ مشروعًا جديدًا عن طريق اختيار إنشاء مشروع جديد.

  3. في الشريط الجانبي ضمن "واجهات برمجة التطبيقات والخدمات"، اختَر بيانات الاعتماد، ثم انقر على إعداد شاشة الموافقة.

    اختَر عنوان بريد إلكتروني وحدِّد اسم منتج واضغط على حفظ.

  4. في علامة التبويب بيانات الاعتماد، اختَر القائمة المنسدلة إنشاء بيانات اعتماد واختَر معرِّف عميل OAuth.

  5. ضِمن نوع التطبيق، اختَر تطبيق الويب.

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

    1. في الحقل مصادر JavaScript المسموح بها، أدخِل مصدر تطبيقك. يمكنك إدخال مصادر متعددة للسماح بتشغيل تطبيقك على بروتوكولات أو نطاقات أو نطاقات فرعية مختلفة. ولا يمكنك استخدام أحرف البدل. في المثال أدناه، قد يكون عنوان URL الثاني هو عنوان URL للإنتاج.

      http://localhost:8080
      https://myproductionurl.example.com
      
    2. لا يتطلب الحقل معرّف الموارد المنتظم (URI) لإعادة التوجيه المعتمَد قيمة. لا يتم استخدام معرفات الموارد المنتظمة (URI) لإعادة التوجيه مع واجهات برمجة تطبيقات JavaScript.

    3. اضغط على الزر إنشاء.

  6. من مربّع الحوار عميل OAuth الناتج، انسخ معرِّف العميل. يتيح معرّف العميل لتطبيقك الوصول إلى Google APIs المفعَّلة.

الخطوة 2: تضمين مكتبة Google Platform في صفحتك

ضمِّن النصوص البرمجية التالية التي تعرض دالة مجهولة المصدر تُدرج نصًا برمجيًا في نموذج العناصر في المستند (DOM) لصفحة الويب هذه على index.html.

<!-- The top of file index.html -->
<html itemscope itemtype="http://schema.org/Article">
<head>
  <!-- BEGIN Pre-requisites -->
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
  </script>
  <script src="https://apis.google.com/js/client:platform.js?onload=start" async defer>
  </script>
  <!-- END Pre-requisites -->

الخطوة 3: إعداد كائن GoogleAuth

حمِّل مكتبة auth2 واستدعِ gapi.auth2.init() لإعداد الكائن GoogleAuth. حدِّد معرِّف العميل الخاص بك والنطاقات التي تريد طلبها عند الاتصال بـ init().

<!-- Continuing the <head> section -->
  <script>
    function start() {
      gapi.load('auth2', function() {
        auth2 = gapi.auth2.init({
          client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
          // Scopes to request in addition to 'profile' and 'email'
          //scope: 'additional_scope'
        });
      });
    }
  </script>
</head>
<body>
  <!-- ... -->
</body>
</html>

الخطوة 4: إضافة زر تسجيل الدخول إلى صفحتك

أضِف زر تسجيل الدخول إلى صفحة الويب، وأرفِق معالج النقرات لطلب البيانات grantOfflineAccess() لبدء مسار الرمز الذي يُستخدَم مرة واحدة.

<!-- Add where you want your sign-in button to render -->
<!-- Use an image that follows the branding guidelines in a real app -->
<button id="signinButton">Sign in with Google</button>
<script>
  $('#signinButton').click(function() {
    // signInCallback defined in step 6.
    auth2.grantOfflineAccess().then(signInCallback);
  });
</script>

الخطوة 5: تسجيل دخول المستخدم

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

{"code":"4/yU4cQZTMnnMtetyFcIWNItG32eKxxxgXXX-Z4yyJJJo.4qHskT-UtugceFc0ZRONyF4z7U4UmAI"}

الخطوة 6: إرسال رمز التفويض إلى الخادم

وcode هو رمزك الذي يمكن استخدامه لمرة واحدة ويمكن للخادم استبداله برمز الدخول الخاص به والرمز المميز لإعادة التحميل. لا يمكنك الحصول على الرمز المميز للتحديث إلا بعد أن يظهر للمستخدم مربع حوار تفويض يطلب الوصول بلا اتصال بالإنترنت. إذا حدّدت prompt select-account في OfflineAccessOptions في الخطوة 4، عليك تخزين الرمز المميّز لإعادة التحميل الذي تسترده لاستخدامه لاحقًا لأنّ عمليات التبادل اللاحقة ستعرض null للرمز المميّز لإعادة التحميل. يوفّر هذا المسار أمانًا أكبر مقارنةً بالتدفق العادي لبروتوكول OAuth 2.0.

يتم دائمًا إرجاع رموز الدخول مع تبادل رمز تفويض صالح.

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

<!-- Last part of BODY element in file index.html -->
<script>
function signInCallback(authResult) {
  if (authResult['code']) {

    // Hide the sign-in button now that the user is authorized, for example:
    $('#signinButton').attr('style', 'display: none');

    // Send the code to the server
    $.ajax({
      type: 'POST',
      url: 'http://example.com/storeauthcode',
      // Always include an `X-Requested-With` header in every AJAX request,
      // to protect against CSRF attacks.
      headers: {
        'X-Requested-With': 'XMLHttpRequest'
      },
      contentType: 'application/octet-stream; charset=utf-8',
      success: function(result) {
        // Handle or verify the server response.
      },
      processData: false,
      data: authResult['code']
    });
  } else {
    // There was an error.
  }
}
</script>

الخطوة 7: استبدال رمز التفويض لرمز الدخول

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

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

مثال:

Java
// (Receive authCode via HTTPS POST)


if (request.getHeader("X-Requested-With") == null) {
  // Without the `X-Requested-With` header, this request could be forged. Aborts.
}

// Set path to the Web application client_secret_*.json file you downloaded from the
// Google API Console: https://console.cloud.google.com/apis/credentials
// You can also find your Web application client ID and client secret from the
// console and specify them directly when you create the GoogleAuthorizationCodeTokenRequest
// object.
String CLIENT_SECRET_FILE = "/path/to/client_secret.json";

// Exchange auth code for access token
GoogleClientSecrets clientSecrets =
    GoogleClientSecrets.load(
        JacksonFactory.getDefaultInstance(), new FileReader(CLIENT_SECRET_FILE));
GoogleTokenResponse tokenResponse =
          new GoogleAuthorizationCodeTokenRequest(
              new NetHttpTransport(),
              JacksonFactory.getDefaultInstance(),
              "https://oauth2.googleapis.com/token",
              clientSecrets.getDetails().getClientId(),
              clientSecrets.getDetails().getClientSecret(),
              authCode,
              REDIRECT_URI)  // Specify the same redirect URI that you use with your web
                             // app. If you don't have a web version of your app, you can
                             // specify an empty string.
              .execute();

String accessToken = tokenResponse.getAccessToken();

// Use access token to call API
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
Drive drive =
    new Drive.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), credential)
        .setApplicationName("Auth Code Exchange Demo")
        .build();
File file = drive.files().get("appfolder").execute();

// Get profile info from ID token
GoogleIdToken idToken = tokenResponse.parseIdToken();
GoogleIdToken.Payload payload = idToken.getPayload();
String userId = payload.getSubject();  // Use this value as a key to identify a user.
String email = payload.getEmail();
boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
String name = (String) payload.get("name");
String pictureUrl = (String) payload.get("picture");
String locale = (String) payload.get("locale");
String familyName = (String) payload.get("family_name");
String givenName = (String) payload.get("given_name");
Python
from apiclient import discovery
import httplib2
from oauth2client import client

# (Receive auth_code by HTTPS POST)


# If this request does not have `X-Requested-With` header, this could be a CSRF
if not request.headers.get('X-Requested-With'):
    abort(403)

# Set path to the Web application client_secret_*.json file you downloaded from the
# Google API Console: https://console.cloud.google.com/apis/credentials
CLIENT_SECRET_FILE = '/path/to/client_secret.json'

# Exchange auth code for access token, refresh token, and ID token
credentials = client.credentials_from_clientsecrets_and_code(
    CLIENT_SECRET_FILE,
    ['https://www.googleapis.com/auth/drive.appdata', 'profile', 'email'],
    auth_code)

# Call Google API
http_auth = credentials.authorize(httplib2.Http())
drive_service = discovery.build('drive', 'v3', http=http_auth)
appfolder = drive_service.files().get(fileId='appfolder').execute()

# Get profile info from ID token
userid = credentials.id_token['sub']
email = credentials.id_token['email']