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

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

قبل ان تبدأ

لتسجيل دخول المستخدمين باستخدام Apple ، قم أولاً بتكوين Sign In with Apple على موقع مطوري Apple ، ثم قم بتمكين Apple كموفر تسجيل الدخول لمشروع Firebase الخاص بك.

انضم إلى برنامج Apple Developer

لا يمكن تكوين تسجيل الدخول باستخدام Apple إلا من قبل أعضاء برنامج Apple Developer Program .

قم بتكوين تسجيل الدخول مع Apple

في موقع Apple Developer ، قم بما يلي:

  1. قم بربط موقع الويب الخاص بك بتطبيقك كما هو موضح في القسم الأول من تكوين تسجيل الدخول باستخدام Apple للويب . عند المطالبة ، قم بتسجيل عنوان URL التالي كعنوان URL للعودة:

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

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

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

  2. قم بإنشاء تسجيل الدخول باستخدام مفتاح Apple الخاص . ستحتاج إلى مفتاحك الخاص الجديد ومعرف المفتاح في القسم التالي.
  3. إذا كنت تستخدم أيًا من ميزات Firebase Authentication التي ترسل رسائل بريد إلكتروني إلى المستخدمين ، بما في ذلك تسجيل الدخول إلى رابط البريد الإلكتروني والتحقق من عنوان البريد الإلكتروني وإلغاء تغيير الحساب وغير ذلك ، فقم بتهيئة خدمة ترحيل البريد الإلكتروني الخاص من Apple وتسجيل noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com (أو مجال قالب البريد الإلكتروني المخصص الخاص بك) حتى تتمكن Apple من ترحيل رسائل البريد الإلكتروني المرسلة بواسطة Firebase Authentication إلى عناوين بريد إلكتروني مجهولة الهوية من 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.

تعامل مع تدفق تسجيل الدخول باستخدام Firebase SDK

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

للتعامل مع تدفق تسجيل الدخول باستخدام Firebase Android SDK ، اتبع الخطوات التالية:

  1. أنشئ مثيلاً لـ OAuthProvider باستخدام Builder الخاص به مع معرف الموفر 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 Auth ، لا تقدم 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 من خلال التعامل مع تدفق تسجيل الدخول إما باستخدام Apple Sign-In JS SDK ، أو إنشاء تدفق OAuth يدويًا أو باستخدام مكتبة OAuth مثل AppAuth .

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

    يمكنك إنشاء رمز 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 لـ nonce مع طلب تسجيل الدخول الخاص بك ، والذي ستمرره Apple دون تغيير في الاستجابة. يتحقق Firebase من الاستجابة عن طريق تجزئة الأصل nonce ومقارنته بالقيمة التي تم تمريرها بواسطة 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 للحصول على بيانات حساب المستخدم.

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

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

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

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

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

لتسجيل خروج مستخدم ، signOut :

Kotlin+KTX

Firebase.auth.signOut()

Java

FirebaseAuth.getInstance().signOut();