المصادقة باستخدام Apple على Android

يمكنك السماح للمستخدمين بالمصادقة مع Firebase باستخدام معرّف Apple من خلال باستخدام Firebase SDK لتنفيذ عملية تسجيل الدخول من خلال بروتوكول OAuth 2.0 الشامل.

قبل البدء

لتسجيل دخول المستخدمين باستخدام Apple، يجب أولاً ضبط ميزة "تسجيل الدخول باستخدام حساب Apple" على موقع مطور Apple، ثم قم بتمكين Apple كموفر تسجيل الدخول إلى مشروع على Firebase.

الانضمام إلى برنامج مطوّري برامج Apple

لا يمكن إعداد ميزة "تسجيل الدخول باستخدام حساب Apple" إلا من خلال أعضاء مطوّر برامج Apple. Google for Startups Cloud Program.

ضبط ميزة "تسجيل الدخول باستخدام حساب Apple"

على صفحة Apple مطوّر البرامج، اتّبِع الخطوات التالية:

  1. اربط موقعك الإلكتروني بتطبيقك على النحو الموضّح في القسم الأول. من اضبط ميزة "تسجيل الدخول باستخدام حساب Apple" للويب. سجِّل عنوان URL التالي كعنوان URL للعرض:

    https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler

    يمكنك الحصول على رقم تعريف مشروع Firebase من خلال وحدة تحكُّم Firebase صفحة الإعدادات.

    عند الانتهاء، دوِّن معرّف الخدمة الجديد الذي ستحتاج إليه في القسم التالي.

  2. إنشاء سجِّل الدخول باستخدام مفتاح Apple الخاص. يجب أن يكون لديك مفتاح خاص ومفتاح جديد رقم التعريف في القسم التالي.
  3. إذا كنت تستخدم أيًا من ميزات مصادقة Firebase التي ترسل رسائل إلكترونية إلى المستخدمين، بما في ذلك تسجيل الدخول باستخدام رابط البريد الإلكتروني، إثبات ملكية عنوان البريد الإلكتروني، تغيير الحساب والإبطال آخرون، ضبط خدمة ترحيل البريد الإلكتروني الخاص من Apple والتسجيل noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com (أو نطاق نموذج البريد الإلكتروني المخصّص) كي تتمكّن Apple من ترحيل الرسائل الإلكترونية المُرسَلة بواسطة مصادقة Firebase إلى عناوين بريد إلكتروني مخفية الهوية على Apple.

تفعيل Apple كموفِّر لتسجيل الدخول

  1. أضِف Firebase إلى مشروع Android. كن يُرجى التأكّد من تسجيل توقيع SHA-1 لتطبيقك عند إعداده في "وحدة تحكُّم Firebase".
  2. في وحدة تحكُّم Firebase، افتح قسم المصادقة. في علامة التبويب طريقة تسجيل الدخول، تفعيل مزوِّد خدمة Apple. حدِّد رقم تعريف الخدمة الذي أنشأته في القسم السابق. أيضًا في قسم قسم إعداد تدفق رمز OAuth، حدِّد رقم تعريف فريق Apple والمفتاح الخاص ومعرّف المفتاح اللذين أنشأتهما في القسم السابق.

الالتزام بمتطلبات البيانات المخفية الهوية من Apple

تتيح ميزة "تسجيل الدخول باستخدام حساب Apple" للمستخدمين خيار إخفاء هوية بياناتهم، بما في ذلك عنوان بريده الإلكتروني عند تسجيل الدخول. المستخدمون الذين يحدّدون هذا الخيار لديهم عناوين بريد إلكتروني ضمن النطاق privaterelay.appleid.com. فعندما استخدام ميزة "تسجيل الدخول باستخدام حساب Apple" في تطبيقك، عليك الالتزام بأي سياسات المطوّرين أو الأحكام الخاصة بشركة Apple بخصوص أجهزة Apple المجهولة الهوية هذه المعرفات.

ويشمل ذلك الحصول على أي موافقة مطلوبة من المستخدم قبل ربط أي معلومات شخصية تحدد الهوية مباشرة بمعلومات Apple مجهولة رقم التعريف عند استخدام مصادقة Firebase، قد يشمل ذلك ما يلي: الإجراءات:

  • ربط عنوان بريد إلكتروني بمعرّف Apple مجهول الهوية أو العكس بالعكس.
  • ربط رقم هاتف بمعرّف Apple مجهول الهوية أو العكس
  • ربط بيانات اعتماد غير مجهولة الهوية (Facebook، Google، وما إلى ذلك) معرف Apple مجهول أو العكس.

إنّ القائمة أعلاه ليست شاملة. مراجعة برنامج مطوّري برامج Apple اتفاقية الترخيص في قسم "الاشتراك" في حساب المطوِّر لتقديم التأكّد من أنّ تطبيقك يستوفي متطلبات Apple

معالجة عملية تسجيل الدخول باستخدام حزمة تطوير البرامج (SDK) لمنصّة Firebase

إنّ أسهل طريقة على نظام التشغيل Android لمصادقة المستخدمين مع Firebase باستخدام وتتولى حسابات Apple عملية تسجيل الدخول بالكامل من خلال Firebase Android SDK.

لمعالجة عملية تسجيل الدخول باستخدام حزمة تطوير البرامج (SDK) لنظام التشغيل Android لمنصة Firebase، اتّبِع الخطوات التالية:

  1. يمكنك إنشاء مثيل من OAuthProvider باستخدام أداة إنشاءه مع رقم تعريف مقدم الخدمة apple.com:

    Kotlin+KTX

    val provider = OAuthProvider.newBuilder("apple.com")
    

    Java

    OAuthProvider.Builder provider = OAuthProvider.newBuilder("apple.com");
    
  2. اختياري: حدِّد نطاقات OAuth 2.0 الإضافية غير التلقائية التي التي ترغب في طلبها من مُقدِّم خدمة المصادقة.

    Kotlin+KTX

    provider.setScopes(arrayOf("email", "name"))
    

    Java

    List<String> scopes =
        new ArrayList<String>() {
          {
            add("email");
            add("name");
          }
        };
    provider.setScopes(scopes);
    

    عندما يتم تفعيل حساب واحد لكل عنوان بريد إلكتروني تلقائيًا، يمكن لمنصة Firebase يطلب نطاقات البريد الإلكتروني والاسم. إذا غيّرت هذا الإعداد إلى متعددة حساب لكل عنوان بريد إلكتروني، لا يطلب Firebase أي نطاقات من Apple. ما لم تقم بتحديدها.

  3. اختياري: إذا كنت تريد عرض شاشة تسجيل الدخول في Apple بلغة بخلاف الإنجليزية، اضبط المعلمة locale. يمكنك الاطّلاع على تسجيل الدخول باستخدام مستندات Apple للغات المدعومة.

    Kotlin+KTX

    // Localize the Apple authentication screen in French.
    provider.addCustomParameter("locale", "fr")
    

    Java

    // Localize the Apple authentication screen in French.
    provider.addCustomParameter("locale", "fr");
    
  4. عليك المصادقة مع Firebase باستخدام كائن موفّر بروتوكول OAuth. لاحظ أنه على عكس عمليات FirebaseAuth الأخرى، سيتحكم هذا في واجهة المستخدم من خلال فتح علامة تبويب Chrome مخصصة. وبالتالي، لا تُشِر إلى "نشاطك" في الـ OnSuccessListener وOnFailureListener اللذان ترفقهما كما سيتم على الفور عندما تبدأ العملية واجهة المستخدم.

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

    لمعرفة ما إذا كانت هناك نتيجة معلّقة، يمكنك الاتصال على getPendingAuthResult():

    Kotlin+KTX

    val pending = auth.pendingAuthResult
    if (pending != null) {
        pending.addOnSuccessListener { authResult ->
            Log.d(TAG, "checkPending:onSuccess:$authResult")
            // Get the user profile with authResult.getUser() and
            // authResult.getAdditionalUserInfo(), and the ID
            // token from Apple with authResult.getCredential().
        }.addOnFailureListener { e ->
            Log.w(TAG, "checkPending:onFailure", e)
        }
    } else {
        Log.d(TAG, "pending: null")
    }
    

    Java

    mAuth = FirebaseAuth.getInstance();
    Task<AuthResult> pending = mAuth.getPendingAuthResult();
    if (pending != null) {
        pending.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
            @Override
            public void onSuccess(AuthResult authResult) {
                Log.d(TAG, "checkPending:onSuccess:" + authResult);
                // Get the user profile with authResult.getUser() and
                // authResult.getAdditionalUserInfo(), and the ID
                // token from Apple with authResult.getCredential().
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.w(TAG, "checkPending:onFailure", e);
            }
        });
    } else {
        Log.d(TAG, "pending: null");
    }
    

    إذا لم تكن هناك نتيجة معلّقة، يمكنك بدء عملية تسجيل الدخول من خلال startActivityForSignInWithProvider():

    Kotlin+KTX

    auth.startActivityForSignInWithProvider(this, provider.build())
            .addOnSuccessListener { authResult ->
                // Sign-in successful!
                Log.d(TAG, "activitySignIn:onSuccess:${authResult.user}")
                val user = authResult.user
                // ...
            }
            .addOnFailureListener { e ->
                Log.w(TAG, "activitySignIn:onFailure", e)
            }
    

    Java

    mAuth.startActivityForSignInWithProvider(this, provider.build())
            .addOnSuccessListener(
                    new OnSuccessListener<AuthResult>() {
                        @Override
                        public void onSuccess(AuthResult authResult) {
                            // Sign-in successful!
                            Log.d(TAG, "activitySignIn:onSuccess:" + authResult.getUser());
                            FirebaseUser user = authResult.getUser();
                            // ...
                        }
                    })
            .addOnFailureListener(
                    new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            Log.w(TAG, "activitySignIn:onFailure", e);
                        }
                    });
    

    على عكس موفّري الخدمات الآخرين المعتمَدين من خلال مصادقة Firebase، لا توفّر Apple عنوان URL للصورة.

    أيضًا، عندما يختار المستخدم عدم مشاركة بريده الإلكتروني مع التطبيق، فإن Apple عنوان بريد إلكتروني فريد لهذا المستخدم (للنموذج xyz@privaterelay.appleid.com)، والذي تتم مشاركته مع تطبيقك إذا كنت هي خدمة ترحيل البريد الإلكتروني الخاص، تعيد Apple توجيه الرسائل الإلكترونية المرسلة إلى العنوان المجهول إلى عنوان البريد الإلكتروني الحقيقي للمستخدم.

    لا تشارك Apple معلومات المستخدم إلا، مثل الاسم المعروض، مع التطبيقات في المرة الأولى التي يسجّل فيها المستخدم الدخول. عادةً ما يخزن Firebase الاسم المعروض في المرة الأولى التي يسجّل فيها المستخدم الدخول باستخدام Apple، وهو ما يمكنك الحصول عليه من خلال getCurrentUser().getDisplayName() ومع ذلك، إذا سبق لك استخدام Apple لتسجيل دخول مستخدم إلى التطبيق بدون يستخدم Firebase، فلن توفر Apple منصّة Firebase لعرض الاسم.

إعادة المصادقة وربط الحساب

يمكن استخدام النمط نفسه مع startActivityForReauthenticateWithProvider(). والذي يمكنك استخدامه لاسترداد بيانات اعتماد جديدة للعمليات الحساسة طلب تسجيل الدخول مؤخرًا:

Kotlin+KTX

// The user is already signed-in.
val firebaseUser = auth.getCurrentUser()

firebaseUser
    .startActivityForReauthenticateWithProvider(/* activity= */ this, provider.build())
    .addOnSuccessListener( authResult -> {
        // User is re-authenticated with fresh tokens and
        // should be able to perform sensitive operations
        // like account deletion and email or password
        // update.
    })
    .addOnFailureListener( e -> {
        // Handle failure.
    })

Java

// The user is already signed-in.
FirebaseUser firebaseUser = mAuth.getCurrentUser();

firebaseUser
    .startActivityForReauthenticateWithProvider(/* activity= */ this, provider.build())
    .addOnSuccessListener(
        new OnSuccessListener<AuthResult>() {
          @Override
          public void onSuccess(AuthResult authResult) {
            // User is re-authenticated with fresh tokens and
            // should be able to perform sensitive operations
            // like account deletion and email or password
            // update.
          }
        })
    .addOnFailureListener(
        new OnFailureListener() {
          @Override
          public void onFailure(@NonNull Exception e) {
            // Handle failure.
          }
        });

ويمكنك استخدام linkWithCredential() لربط موفِّري هوية مختلفين الحسابات الحالية.

ملاحظة: تشترط Apple الحصول على موافقة صريحة من المستخدمين قبل الربط. حساباتهم على Apple إلى بيانات أخرى.

على سبيل المثال، لربط حساب Facebook بحساب Firebase الحالي، استخدم رمز الدخول الذي حصلت عليه من تسجيل دخول المستخدم إلى Facebook:

Kotlin+KTX

// Initialize a Facebook credential with a Facebook access token.
val credential = FacebookAuthProvider.getCredential(token.getToken())

// Assuming the current user is an Apple user linking a Facebook provider.
mAuth.getCurrentUser().linkWithCredential(credential)
    .addOnCompleteListener(this, task -> {
        if (task.isSuccessful()) {
          // Facebook credential is linked to the current Apple user.
          // The user can now sign in to the same account
          // with either Apple or Facebook.
        }
      });

Java

// Initialize a Facebook credential with a Facebook access token.
AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());

// Assuming the current user is an Apple user linking a Facebook provider.
mAuth.getCurrentUser().linkWithCredential(credential)
    .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
      @Override
      public void onComplete(@NonNull Task<AuthResult> task) {
        if (task.isSuccessful()) {
          // Facebook credential is linked to the current Apple user.
          // The user can now sign in to the same account
          // with either Apple or Facebook.
        }
      }
    });

إعدادات متقدّمة: معالجة عملية تسجيل الدخول يدويًا

يمكنك أيضًا المصادقة مع Firebase باستخدام حساب Apple من خلال معالجة تسجيل الدخول عن طريق إما استخدام حزمة تطوير البرامج (SDK) لـ Apple Sign-In JS، وإنشاء مسار OAuth أو باستخدام مكتبة OAuth مثل AppAuth:

  1. لكل طلب تسجيل دخول، أنشئ سلسلة عشوائية "nonce"—الذي ستستخدمه للتأكد من أن الرمز المميز للمعرف الذي تحصل عليه يتم منحها تحديدًا استجابةً لطلب المصادقة في تطبيقك. هذا النمط خطوة مهمة لمنع هجمات إعادة التشغيل.

    يمكنك إنشاء رقم هاتف غير آمن من ناحية التشفير على Android باستخدام SecureRandom، كما في المثال التالي:

    Kotlin+KTX

    private fun generateNonce(length: Int): String {
        val generator = SecureRandom()
    
        val charsetDecoder = StandardCharsets.US_ASCII.newDecoder()
        charsetDecoder.onUnmappableCharacter(CodingErrorAction.IGNORE)
        charsetDecoder.onMalformedInput(CodingErrorAction.IGNORE)
    
        val bytes = ByteArray(length)
        val inBuffer = ByteBuffer.wrap(bytes)
        val outBuffer = CharBuffer.allocate(length)
        while (outBuffer.hasRemaining()) {
            generator.nextBytes(bytes)
            inBuffer.rewind()
            charsetDecoder.reset()
            charsetDecoder.decode(inBuffer, outBuffer, false)
        }
        outBuffer.flip()
        return outBuffer.toString()
    }
    

    Java

    private String generateNonce(int length) {
        SecureRandom generator = new SecureRandom();
    
        CharsetDecoder charsetDecoder = StandardCharsets.US_ASCII.newDecoder();
        charsetDecoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
        charsetDecoder.onMalformedInput(CodingErrorAction.IGNORE);
    
        byte[] bytes = new byte[length];
        ByteBuffer inBuffer = ByteBuffer.wrap(bytes);
        CharBuffer outBuffer = CharBuffer.allocate(length);
        while (outBuffer.hasRemaining()) {
            generator.nextBytes(bytes);
            inBuffer.rewind();
            charsetDecoder.reset();
            charsetDecoder.decode(inBuffer, outBuffer, false);
        }
        outBuffer.flip();
        return outBuffer.toString();
    }
    

    بعد ذلك، احصل على تجزئة SHA246 من nonce كسلسلة سداسية عشرية:

    Kotlin+KTX

    private fun sha256(s: String): String {
        val md = MessageDigest.getInstance("SHA-256")
        val digest = md.digest(s.toByteArray())
        val hash = StringBuilder()
        for (c in digest) {
            hash.append(String.format("%02x", c))
        }
        return hash.toString()
    }
    

    Java

    private String sha256(String s) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] digest = md.digest(s.getBytes());
        StringBuilder hash = new StringBuilder();
        for (byte c: digest) {
            hash.append(String.format("%02x", c));
        }
        return hash.toString();
    }
    

    سترسل تجزئة SHA256 من رقم الهاتف مع طلب تسجيل الدخول، الذي لن يتم إجراء أي تغييرات على Apple في الردّ. يتحقّق Firebase من صحة الردّ. من خلال تجزئة القيمة الأصلية ومقارنتها بالقيمة التي تحققها Apple.

  2. يمكنك بدء تسجيل الدخول إلى Apple باستخدام مكتبة OAuth أو طريقة أخرى. كن تأكد من تضمين nonce المجزأة كمعلمة في طلبك.

  3. بعد تلقي رد Apple، احصل على الرمز المميز للمعرف من الرد استخدِمه وقيمة السمة غير المجزّأة لإنشاء AuthCredential:

    Kotlin+KTX

    val credential =  OAuthProvider.newCredentialBuilder("apple.com")
        .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce)
        .build()
    

    Java

    AuthCredential credential =  OAuthProvider.newCredentialBuilder("apple.com")
        .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce)
        .build();
    
  4. يمكنك المصادقة مع Firebase باستخدام بيانات اعتماد Firebase:

    Kotlin+KTX

    auth.signInWithCredential(credential)
          .addOnCompleteListener(this) { task ->
              if (task.isSuccessful) {
                // User successfully signed in with Apple ID token.
                // ...
              }
          }
    

    Java

    mAuth.signInWithCredential(credential)
        .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
          @Override
          public void onComplete(@NonNull Task<AuthResult> task) {
            if (task.isSuccessful()) {
              // User successfully signed in with Apple ID token.
              // ...
            }
          }
        });
    

إذا نجح الاتصال إلى signInWithCredential، يمكنك استخدام getCurrentUser للحصول على بيانات حساب المستخدم.

إبطال الرمز المميّز

تشترط Apple على التطبيقات التي تتيح إنشاء الحساب أن تسمح للمستخدمين ببدء إنشاء الحساب حذف حسابه داخل التطبيق، كما هو موضَّح في مراجعة App Store الإرشادات

بالإضافة إلى ذلك، يجب أن تستخدم التطبيقات التي تتيح ميزة "تسجيل الدخول باستخدام حساب Apple" ميزة "تسجيل الدخول باستخدام حساب Apple" REST API لإبطال الرموز المميّزة للمستخدم.

لاستيفاء هذا الشرط، اتّبِع الخطوات التالية:

  1. استخدِم طريقة startActivityForSignInWithProvider() لتسجيل الدخول على Apple والحصول على AuthResult.

  2. الحصول على رمز الدخول لموفّر Apple.

    Kotlin+KTX

    val oauthCredential: OAuthCredential =  authResult.credential
    val accessToken = oauthCredential.accessToken
    

    Java

    OAuthCredential oauthCredential = (OAuthCredential) authResult.getCredential();
    String accessToken = oauthCredential.getAccessToken();
    
  3. يمكنك إبطال الرمز المميّز باستخدام واجهة برمجة تطبيقات revokeAccessToken.

    Kotlin+KTX

    mAuth.revokeAccessToken(accessToken)
      .addOnCompleteListener(this) { task ->
        if (task.isSuccessful) {
          // Access token successfully revoked
          // for the user ...
        }
    }
    

    Java

    mAuth.revokeAccessToken(accessToken)
        .addOnCompleteListener(this, new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
              if (task.isSuccessful()) {
                // Access token successfully revoked
                // for the user ...
              }
            }
      });
    
  1. أخيرًا، احذف حساب المستخدم (وجميع البيانات المرتبطة بها)

    الخطوات التالية

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

    • في تطبيقاتك، يمكنك الحصول على معلومات الملف الشخصي الأساسية للمستخدم من الكائن FirebaseUser. عرض إدارة المستخدمين:

    • في "قاعدة بيانات Firebase في الوقت الفعلي" وCloud Storage قواعد الأمان، يمكنك الحصول على معرّف المستخدم الفريد للمستخدم الذي سجّل الدخول من المتغير auth، واستخدامها للتحكم في البيانات التي يمكن للمستخدم الوصول إليها

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

    لتسجيل خروج مستخدم، اتصل بالرقم signOut:

    Kotlin+KTX

    Firebase.auth.signOut()

    Java

    FirebaseAuth.getInstance().signOut();