تسجيل الدخول إلى الحساب المرتبط على أجهزة Android

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

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

وستتعرف في هذا المستند على كيفية تعديل تطبيق Android تسجيل الدخول إلى حساب مرتبط

آلية العمل

  1. يمكنك الموافقة على عرض الحسابات المرتبطة أثناء تسجيل الدخول بنقرة واحدة.
  2. إذا سجّل المستخدم الدخول على Google وربط حسابه على Google حسابه على خدمتك، فسيتم عرض رمز مميز لرقم التعريف الحساب.
  3. يظهر للمستخدم رسالة تطلب منك تسجيل الدخول بنقرة واحدة مع خيار تسجيل الدخول إلى الخدمة باستخدام حسابهم المرتبط.
  4. إذا اختار المستخدم المتابعة باستخدام الحساب المرتبط، سيظهر الرمز المميز لمعرّف المستخدم. إلى تطبيقك. يمكنك مطابقة ذلك مع الرمز المميز الذي تم إرساله إلى في الخطوة 2 لتحديد المستخدم الذي سجّل الدخول.

ضبط إعدادات الجهاز

إعداد بيئة التطوير

احصل على أحدث "خدمات Google Play" من خلال مضيف التطوير:

  1. افتح إدارة حزمة تطوير البرامج (SDK) لنظام التشغيل Android
  1. ضمن أدوات حزمة تطوير البرامج (SDK)، ابحث عن خدمات Google Play.

  2. إذا كانت حالة هذه الحزم غير مثبّتة، فحدد كلتيهما وانقر على تثبيت الحِزم:

إعداد تطبيقك

  1. في ملف build.gradle على مستوى مشروعك، أضِف مستودع Maven من Google. في كل من القسمين buildscript وallprojects.

    buildscript {
        repositories {
            google()
        }
    }
    
    allprojects {
        repositories {
            google()
        }
    }
    
  2. إضافة الموارد التابعة لـ "الربط بـ Google" واجهة برمجة التطبيقات (API) في الوحدة ملف Gradle على مستوى التطبيق، ويكون عادةً app/build.gradle:

    dependencies {
      implementation 'com.google.android.gms:play-services-auth:21.2.0'
    }
    

تعديل تطبيق Android لإتاحة تسجيل الدخول باستخدام حساب مرتبط

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

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

  1. إنشاء نشاط لتلقّي نتيجة القصد من تسجيل الدخول

    Kotlin

      private val activityResultLauncher = registerForActivityResult(
        ActivityResultContracts.StartIntentSenderForResult()) { result ->
        if (result.resultCode == RESULT_OK) {
          try {
            val signInCredentials = Identity.signInClient(this)
                                    .signInCredentialFromIntent(result.data)
            // Review the Verify the integrity of the ID token section for
            // details on how to verify the ID token
            verifyIdToken(signInCredential.googleIdToken)
          } catch (e: ApiException) {
            Log.e(TAG, "Sign-in failed with error code:", e)
          }
        } else {
          Log.e(TAG, "Sign-in failed")
        }
      }
    

    Java

      private final ActivityResultLauncher<IntentSenderResult>
        activityResultLauncher = registerForActivityResult(
        new ActivityResultContracts.StartIntentSenderForResult(),
        result -> {
        If (result.getResultCode() == RESULT_OK) {
            try {
              SignInCredential signInCredential = Identity.getSignInClient(this)
                             .getSignInCredentialFromIntent(result.getData());
              verifyIdToken(signInCredential.getGoogleIdToken());
            } catch (e: ApiException ) {
              Log.e(TAG, "Sign-in failed with error:", e)
            }
        } else {
            Log.e(TAG, "Sign-in failed")
        }
    });
    
  2. إنشاء طلب تسجيل الدخول

    Kotlin

    private val tokenRequestOptions =
    GoogleIdTokenRequestOptions.Builder()
      .supported(true)
      // Your server's client ID, not your Android client ID.
      .serverClientId(getString("your-server-client-id")
      .filterByAuthorizedAccounts(true)
      .associateLinkedAccounts("service-id-of-and-defined-by-developer",
                               scopes)
      .build()
    

    Java

     private final GoogleIdTokenRequestOptions tokenRequestOptions =
         GoogleIdTokenRequestOptions.Builder()
      .setSupported(true)
      .setServerClientId("your-service-client-id")
      .setFilterByAuthorizedAccounts(true)
      .associateLinkedAccounts("service-id-of-and-defined-by-developer",
                                scopes)
      .build()
    
  3. فتح رسالة الغرض من تسجيل الدخول في انتظار المراجعة

    Kotlin

     Identity.signInClient(this)
        .beginSignIn(
      BeginSignInRequest.Builder()
        .googleIdTokenRequestOptions(tokenRequestOptions)
      .build())
        .addOnSuccessListener{result ->
          activityResultLauncher.launch(result.pendingIntent.intentSender)
      }
      .addOnFailureListener {e ->
        Log.e(TAG, "Sign-in failed because:", e)
      }
    

    Java

     Identity.getSignInClient(this)
      .beginSignIn(
        BeginSignInRequest.Builder()
          .setGoogleIdTokenRequestOptions(tokenRequestOptions)
          .build())
      .addOnSuccessListener(result -> {
        activityResultLauncher.launch(
            result.getPendingIntent().getIntentSender());
    })
    .addOnFailureListener(e -> {
      Log.e(TAG, "Sign-in failed because:", e);
    });
    

التأكّد من صحة الرمز المميّز للمعرّف

للتحقّق من صلاحية الرمز المميّز، تأكَّد مما يلي: المعايير:

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

باستخدام الحقول email وemail_verified وhd، يمكنك تحديد ما إذا كان تستضيف Google عنوان بريد إلكتروني وموثوقًا به. في الحالات التي تكون فيها Google موثوقة، يكون المستخدم معروفًا كمالك الحساب الشرعي، ويمكنك تخطي كلمة المرور أو طرق التحدي.

الحالات التي تكون فيها Google موثوقة:

  • السمة email هي اللاحقة @gmail.com، وهذا حساب Gmail.
  • email_verified صحيح وتم ضبط hd، هذا حساب G Suite.

يمكن للمستخدمين التسجيل للحصول على حسابات Google بدون استخدام Gmail أو G Suite. فعندما لا يحتوي email على اللاحقة @gmail.com وhd غير موجود، كما أن Google لا موثوقة وكلمة المرور أو طرق التحقق الأخرى للتحقق المستخدم. يمكن أن يكون email_verified صحيحًا أيضًا لأن Google تحققت في البداية من صحة المستخدم عند إنشاء حساب Google، ولكن ملكية الجهة الخارجية ربما تغير حساب بريدك الإلكتروني منذ ذلك الحين.

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

استخدام مكتبة برامج Google API

إنّ استخدام مكتبة Java Google API Client Library هو الطريقة المقترَحة للتحقّق من صحة رموز تعريف Google في بيئة الإنتاج.

Java

  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

إذا كنت بحاجة إلى التحقّق من أنّ الرمز المميّز للمعرّف يمثّل Google Workspace أو Cloud حساب مؤسسة، يمكنك إثبات ملكية المطالبة hd من خلال التحقّق من اسم النطاق. التي يتم إرجاعها باستخدام الطريقة Payload.getHostedDomain().

调用 tokeninfo 端点

调试验证 ID 令牌签名的一种简单方法是 使用 tokeninfo 端点。调用此端点涉及 这个额外的网络请求会为您完成大部分的验证工作, 验证和载荷提取。不适合在生产环境中使用 因为请求可能会受到限制或出现间歇性错误。

如需使用 tokeninfo 端点验证 ID 令牌,请创建 HTTPS POST 或 GET 请求发送到端点,并在 id_token 参数。 例如,要验证令牌“XYZ123”,请发出以下 GET 请求:

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

如果令牌经过正确签名,并且 issexp 具有预期值,就会收到 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"
}

如果您需要验证 ID 令牌是否代表 Google Workspace 账号,可以先查看 hd 声明,指示用户的托管网域。只有在以下情况下, 从而仅允许特定网域中的成员访问资源。缺少此声明 表示该账号不属于 Google Workspace 托管网域。