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

لاستخدام خدمات Google نيابةً عن مستخدم عندما يكون غير متصل بالإنترنت، عليك استخدام مسار مختلط من جهة الخادم حيث يفوّض المستخدم تطبيقك من جهة العميل باستخدام عميل JavaScript API وترسل رمز تفويضًا خاصًا لمرة واحدة إلى خادمك. يتبادل خادمك هذا الرمز الذي يُستخدم لمرة واحدة للحصول على الرموز المميزة للدخول وإعادة التحميل من 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 في صفحتك

ضمِّن النصوص البرمجية التالية التي توضح دالة مجهولة المصدر تعمل على إدراج نص برمجي في نموذج العناصر في المستند (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']