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

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

قبل ان تبدأ

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

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

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

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

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

  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 Developer في قسم العضوية في حساب المطور الخاص بك للتأكد من أن تطبيقك يلبي متطلبات Apple.

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

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

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

  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 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" - والتي ستستخدمها للتأكد من أن رمز المعرف الذي تحصل عليه قد تم منحه خصيصًا استجابة لطلب مصادقة تطبيقك. هذه الخطوة مهمة لمنع هجمات الإعادة.

    يمكنك إنشاء رقم آمن تشفيريًا على 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 أو أي طريقة أخرى. تأكد من تضمين الرقم المجزأ كمعلمة في طلبك.

  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 أن تسمح التطبيقات التي تدعم إنشاء الحساب للمستخدمين ببدء حذف حساباتهم داخل التطبيق، كما هو موضح في إرشادات مراجعة متجر التطبيقات

بالإضافة إلى ذلك، يجب على التطبيقات التي تدعم تسجيل الدخول باستخدام 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 API.

    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 Realtime وقواعد أمان التخزين السحابي، يمكنك الحصول على معرف المستخدم الفريد للمستخدم الذي قام بتسجيل الدخول من متغير auth ، واستخدامه للتحكم في البيانات التي يمكن للمستخدم الوصول إليها.

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

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

    Kotlin+KTX

    Firebase.auth.signOut()

    Java

    FirebaseAuth.getInstance().signOut();