المصادقة مع خادم خلفي

إذا كنت تستخدم Google Sign-In مع تطبيق أو موقع يتصل بخادم خلفية ، فقد تحتاج إلى تحديد المستخدم المسجل الدخول حاليًا على الخادم. للقيام بذلك بشكل آمن ، بعد أن يقوم المستخدم بتسجيل الدخول بنجاح ، أرسل رمز معرف المستخدم إلى الخادم الخاص بك باستخدام HTTPS. بعد ذلك ، على الخادم ، تحقق من سلامة الرمز المميز للمعرف واستخدم معلومات المستخدم الموجودة في الرمز المميز لإنشاء جلسة أو إنشاء حساب جديد.

أرسل رمز المعرف إلى الخادم الخاص بك

أولاً ، عندما يقوم المستخدم بتسجيل الدخول ، احصل على رمز معرفه المميز:

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

    // Request only the user's ID token, which can be used to identify the
    // user securely to your backend. This will contain the user's basic
    // profile (name, profile picture URL, etc) so you should not need to
    // make an additional call to personalize your application.
    GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(getString(R.string.server_client_id))
            .requestEmail()
            .build();
  2. عند بدء تشغيل تطبيقك ، تحقق مما إذا كان المستخدم قد سجل الدخول بالفعل إلى تطبيقك باستخدام Google ، على هذا الجهاز أو أي جهاز آخر ، عن طريق الاتصال بـ silentSignIn :

    GoogleSignIn.silentSignIn()
        .addOnCompleteListener(
            this,
            new OnCompleteListener<GoogleSignInAccount>() {
              @Override
              public void onComplete(@NonNull Task<GoogleSignInAccount> task) {
                handleSignInResult(task);
              }
            });
  3. إذا لم يتمكن المستخدم من تسجيل الدخول بصمت ، GoogleSignInAccount تجربة تسجيل الخروج العادية ، مع منح المستخدم خيار تسجيل الدخول. عندما يقوم المستخدم GoogleSignInAccount الدخول ، احصل على حساب GoogleSignInAccount الخاص GoogleSignInAccount في نتيجة النشاط لنية تسجيل الدخول:

    // This task is always completed immediately, there is no need to attach an
    // asynchronous listener.
    Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
    handleSignInResult(task);
  4. بعد أن يقوم المستخدم GoogleSignInAccount الدخول بصمت أو بشكل صريح ، احصل على رمز المعرف المميز من كائن GoogleSignInAccount :

    private void handleSignInResult(@NonNull Task<GoogleSignInAccount> completedTask) {
        try {
            GoogleSignInAccount account = completedTask.getResult(ApiException.class);
            String idToken = account.getIdToken();
    
            // TODO(developer): send ID Token to server and validate
    
            updateUI(account);
        } catch (ApiException e) {
            Log.w(TAG, "handleSignInResult:error", e);
            updateUI(null);
        }
    }

بعد ذلك ، أرسل رمز المعرف المميز إلى الخادم الخاص بك مع طلب HTTPS POST:

HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("https://yourbackend.example.com/tokensignin");

try {
  List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
  nameValuePairs.add(new BasicNameValuePair("idToken", idToken));
  httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

  HttpResponse response = httpClient.execute(httpPost);
  int statusCode = response.getStatusLine().getStatusCode();
  final String responseBody = EntityUtils.toString(response.getEntity());
  Log.i(TAG, "Signed in as: " + responseBody);
} catch (ClientProtocolException e) {
  Log.e(TAG, "Error sending ID token to backend.", e);
} catch (IOException e) {
  Log.e(TAG, "Error sending ID token to backend.", e);
}

تحقق من سلامة الرمز المميز للمعرف

بعد أن تتلقى الرمز المميز للمعرف بواسطة HTTPS POST ، يجب عليك التحقق من سلامة الرمز المميز. للتحقق من صلاحية الرمز المميز ، تأكد من استيفاء المعايير التالية:

  • تم توقيع رمز المعرف بشكل صحيح بواسطة Google. استخدم مفاتيح Google العامة (المتوفرة بتنسيق JWK أو PEM ) للتحقق من توقيع الرمز المميز. يتم تدوير هذه المفاتيح بانتظام ؛ افحص رأس Cache-Control في الاستجابة لتحديد متى يجب استعادتها مرة أخرى.
  • تساوي قيمة aud في الرمز المميز للمعرف أحد معرّفات عملاء تطبيقك. يعد هذا الفحص ضروريًا لمنع استخدام الرموز المميزة التي تم إصدارها لتطبيق ضار للوصول إلى البيانات الخاصة بنفس المستخدم على خادم الواجهة الخلفية للتطبيق.
  • قيمة iss في الرمز المميز ID تساوي accounts.google.com أو https://accounts.google.com .
  • لم يمر وقت انتهاء الصلاحية ( exp ) exp المميز للمعرف.
  • إذا كنت ترغب في تقييد الوصول إلى أعضاء نطاق G Suite فقط ، فتحقق من أن رمز المعرف المميز لديه مطالبة hd تطابق اسم نطاق G Suite.

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

استخدام مكتبة Google API Client

يعد استخدام إحدى مكتبات Google API Client (مثل Java و Node.js و PHP و Python ) هو الطريقة الموصى بها للتحقق من الرموز المميزة لمعرف Google في بيئة الإنتاج.

جافا

للتحقق من صحة رمز مميز للمعرف في جافا ، استخدم كائن GoogleIdTokenVerifier . على سبيل المثال:

import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;

...

GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
    // Specify the CLIENT_ID of the app that accesses the backend:
    .setAudience(Collections.singletonList(CLIENT_ID))
    // Or, if multiple clients access the backend:
    //.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
    .build();

// (Receive idTokenString by HTTPS POST)

GoogleIdToken idToken = verifier.verify(idTokenString);
if (idToken != null) {
  Payload payload = idToken.getPayload();

  // Print user identifier
  String userId = payload.getSubject();
  System.out.println("User ID: " + userId);

  // Get profile information from payload
  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");

  // Use or store profile information
  // ...

} else {
  System.out.println("Invalid ID token.");
}

و GoogleIdTokenVerifier.verify() يتحقق طريقة التوقيع JWT، و aud المطالبة، و iss المطالبة، و exp المطالبة.

إذا كنت تريد تقييد الوصول إلى أعضاء نطاق G Suite الخاص بك فقط ، فتحقق أيضًا من المطالبة hd عن طريق التحقق من اسم النطاق الذي يتم إرجاعه بواسطة طريقة Payload.getHostedDomain() .

Node.js

للتحقق من صحة رمز مميز للمعرف في Node.js ، استخدم مكتبة مصادقة Google لـ Node.js. قم بتثبيت المكتبة:

npm install google-auth-library --save
بعد ذلك ، قم باستدعاء وظيفة verifyIdToken() . على سبيل المثال:

const {OAuth2Client} = require('google-auth-library');
const client = new OAuth2Client(CLIENT_ID);
async function verify() {
  const ticket = await client.verifyIdToken({
      idToken: token,
      audience: CLIENT_ID,  // Specify the CLIENT_ID of the app that accesses the backend
      // Or, if multiple clients access the backend:
      //[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
  });
  const payload = ticket.getPayload();
  const userid = payload['sub'];
  // If request specified a G Suite domain:
  // const domain = payload['hd'];
}
verify().catch(console.error);

و verifyIdToken يتحقق وظيفة التوقيع JWT، و aud الدعوى و exp المطالبة، و iss المطالبة.

إذا كنت ترغب في تقييد الوصول لأعضاء نطاق G Suite فقط ، فتحقق أيضًا من أن المطالبة hd تطابق اسم نطاق G Suite.

بي أتش بي

للتحقق من صحة رمز مميز للمعرف في PHP ، استخدم مكتبة عميل واجهة برمجة تطبيقات Google لـ PHP . قم بتثبيت المكتبة (على سبيل المثال ، باستخدام Composer):

composer require google/apiclient
ثم قم باستدعاء وظيفة verifyIdToken() . على سبيل المثال:

require_once 'vendor/autoload.php';

// Get $id_token via HTTPS POST.

$client = new Google_Client(['client_id' => $CLIENT_ID]);  // Specify the CLIENT_ID of the app that accesses the backend
$payload = $client->verifyIdToken($id_token);
if ($payload) {
  $userid = $payload['sub'];
  // If request specified a G Suite domain:
  //$domain = $payload['hd'];
} else {
  // Invalid ID token
}

و verifyIdToken يتحقق وظيفة التوقيع JWT، و aud الدعوى و exp المطالبة، و iss المطالبة.

إذا كنت ترغب في تقييد الوصول لأعضاء نطاق G Suite فقط ، فتحقق أيضًا من أن المطالبة hd تطابق اسم نطاق G Suite.

بايثون

للتحقق من صحة رمز مميز للمعرّف في Python ، استخدم وظيفة check_oauth2_token . على سبيل المثال:

from google.oauth2 import id_token
from google.auth.transport import requests

# (Receive token by HTTPS POST)
# ...

try:
    # Specify the CLIENT_ID of the app that accesses the backend:
    idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID)

    # Or, if multiple clients access the backend server:
    # idinfo = id_token.verify_oauth2_token(token, requests.Request())
    # if idinfo['aud'] not in [CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]:
    #     raise ValueError('Could not verify audience.')

    # If auth request is from a G Suite domain:
    # if idinfo['hd'] != GSUITE_DOMAIN_NAME:
    #     raise ValueError('Wrong hosted domain.')

    # ID token is valid. Get the user's Google Account ID from the decoded token.
    userid = idinfo['sub']
except ValueError:
    # Invalid token
    pass

و verify_oauth2_token يتحقق وظيفة التوقيع JWT، و aud المطالبة، و exp المطالبة. يجب عليك أيضًا التحقق من مطالبة hd (إن أمكن) عن طريق فحص الكائن الذي يُرجع verify_oauth2_token . في حالة وصول عدة عملاء إلى خادم الواجهة الخلفية ، تحقق أيضًا يدويًا من مطالبة aud .

استدعاء نقطة نهاية tokeninfo

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

للتحقق من صحة رمز مميز للمعرف باستخدام نقطة نهاية tokeninfo ، قم بإجراء طلب HTTPS POST أو GET إلى نقطة النهاية ، وقم بتمرير رمز ID الخاص بك في المعلمة id_token . على سبيل المثال ، للتحقق من الرمز المميز "XYZ123" ، قم بإجراء طلب GET التالي:

https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123

إذا تم التوقيع على المنوال صحيح و iss و exp مطالبات لديهم القيم المتوقعة، سوف تحصل على استجابة HTTP 200، حيث يحتوي جسم مطالبات رمزية تنسيق JSON-ID. إليك مثال على الرد:

{
 // These six fields are included in all Google ID Tokens.
 "iss": "https://accounts.google.com",
 "sub": "110169484474386276334",
 "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "iat": "1433978353",
 "exp": "1433981953",

 // These seven fields are only included when the user has granted the "profile" and
 // "email" OAuth scopes to the application.
 "email": "testuser@gmail.com",
 "email_verified": "true",
 "name" : "Test User",
 "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
 "given_name": "Test",
 "family_name": "User",
 "locale": "en"
}

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

قم بإنشاء حساب أو جلسة

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

تأمين حسابات المستخدمين الخاصة بك مع Cross Account Protection

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