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

إذا سبق لك الترقية إلى Firebase Authentication with Identity Platform، يمكنك مصادقة المستخدمين باستخدام Firebase من خلال موفّر اتصال OpenID ‏ (OIDC) المتوافق الذي تختاره. ويتيح ذلك استخدام موفّري الهوية غير المتوافقين أصلاً مع Firebase.

قبل البدء

لتسجيل دخول المستخدمين باستخدام موفّر OIDC، عليك أولاً جمع بعض المعلومات من الموفّر:

  • معرّف العميل: سلسلة فريدة للموفّر تحدّد تطبيقك. قد يمنحك الموفّر معرّف عميل مختلفًا لكل منصة تستخدمها. وهذه إحدى قيم طلب aud في رموز التعريف التي يصدرها الموفّر.

  • الرمز السري للعميل: سلسلة سرية يستخدمها الموفّر لتأكيد ملكية معرّف العميل. لكل معرّف عميل، ستحتاج إلى رمز سري مطابق للعميل. (هذه القيمة مطلوبة فقط إذا كنت تستخدم مسار رمز التفويض ، وهو مسار يُنصح به بشدة.)

  • جهة الإصدار: سلسلة تحدّد الموفّر. يجب أن تكون هذه القيمة عنوان URL ، وعند إلحاقها بـ /.well-known/openid-configuration، يصبح عنوان مستند اكتشاف OIDC الخاص بالموفّر. على سبيل المثال، إذا كانت جهة الإصدار هي https://auth.example.com، يجب أن يكون مستند الاكتشاف متاحًا على https://auth.example.com/.well-known/openid-configuration.

بعد الحصول على المعلومات أعلاه، فعِّل اتصال OpenID كموفّر لتسجيل الدخول في مشروع Firebase الخاص بك:

  1. أضِف Firebase إلى مشروع Android.

  2. إذا لم يسبق لك الترقية إلى Firebase Authentication with Identity Platform، عليك إجراء ذلك. لا تتوفّر مصادقة OpenID Connect إلا في المشاريع التي تمّت ترقيتها.

  3. في صفحة موفّرو تسجيل الدخول ضمن Firebase Console، انقر على إضافة موفّر جديد، ثم على اتصال OpenID.

  4. اختَر ما إذا كنت ستستخدم مسار رمز التفويض أو مسار المنحة الضمنية.

    يجب استخدام مسار الرمز دائمًا إذا كان الموفّر يتيحه. يكون التدفّق الضمني أقل أمانًا ويُنصح بشدة بعدم استخدامه.

  5. امنح اسمًا لهذا الموفّر. دوِّن رقم تعريف الموفّر الذي تم إنشاؤه، مثل oidc.example-provider. ستحتاج إلى هذا الرقم التعريفي عند إضافة رمز تسجيل الدخول إلى تطبيقك.

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

  7. احفظ التغييرات.

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

إذا كنت تعمل على إنشاء تطبيق Android، فإنّ أسهل طريقة لمصادقة المستخدمين باستخدام Firebase من خلال موفّر OIDC هي التعامل مع مسار تسجيل الدخول بالكامل باستخدام Firebase Android SDK.

للتعامل مع مسار تسجيل الدخول باستخدام Firebase Android SDK، اتّبِع الخطوات التالية:

  1. أنشِئ مثيلاً من OAuthProvider باستخدام المنشئ مع رقم تعريف الموفّر

    Kotlin

    val providerBuilder = OAuthProvider.newBuilder("oidc.example-provider")

    Java

    OAuthProvider.Builder providerBuilder = OAuthProvider.newBuilder("oidc.example-provider");

  2. اختياري: حدِّد مَعلمات OAuth المخصّصة الإضافية التي تريد إرسالها مع طلب OAuth.

    Kotlin

    // Target specific email with login hint.
    providerBuilder.addCustomParameter("login_hint", "user@example.com")

    Java

    // Target specific email with login hint.
    providerBuilder.addCustomParameter("login_hint", "user@example.com");

    راجِع موفّر OIDC لمعرفة المَعلمات التي يتيحها. يُرجى العِلم أنّه لا يمكنك تمرير المَعلمات المطلوبة من Firebase باستخدام setCustomParameters(). هذه المَعلمات هي client_id، response_type، redirect_uri، state، scope و response_mode.

  3. اختياري: حدِّد نطاقات OAuth 2.0 الإضافية التي تريد طلبها من موفّر المصادقة، بالإضافة إلى النطاق الأساسي للملف الشخصي.

    Kotlin

    // Request read access to a user's email addresses.
    // This must be preconfigured in the app's API permissions.
    providerBuilder.scopes = listOf("mail.read", "calendars.read")

    Java

    // Request read access to a user's email addresses.
    // This must be preconfigured in the app's API permissions.
    List<String> scopes =
            new ArrayList<String>() {
                {
                    add("mail.read");
                    add("calendars.read");
                }
            };
    providerBuilder.setScopes(scopes);

    راجِع موفّر OIDC لمعرفة النطاقات التي يستخدمها.

  4. صادِق باستخدام Firebase من خلال عنصر موفّر OAuth. يُرجى العِلم أنّه على عكس عمليات FirebaseAuth الأخرى، ستتحكّم هذه العملية في واجهة المستخدم من خلال عرض علامة تبويب مخصّصة في Chrome. نتيجةً لذلك، لا تشِر إلى النشاط في OnSuccessListener وOnFailureListener اللذين تربطهما، لأنّهما سيتم فصلهما على الفور عند بدء العملية لواجهة المستخدم.

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

    للتحقّق مما إذا كانت هناك نتيجة معلّقة، استخدِم getPendingAuthResult:

    Kotlin

    val pendingResultTask = firebaseAuth.pendingAuthResult
    if (pendingResultTask != null) {
        // There's something already here! Finish the sign-in for your user.
        pendingResultTask
            .addOnSuccessListener {
                // User is signed in.
                // IdP data available in
                // authResult.getAdditionalUserInfo().getProfile().
                // The OAuth access token can also be retrieved:
                // ((OAuthCredential)authResult.getCredential()).getAccessToken().
                // The OAuth secret can be retrieved by calling:
                // ((OAuthCredential)authResult.getCredential()).getSecret().
            }
            .addOnFailureListener {
                // Handle failure.
            }
    } else {
        // There's no pending result so you need to start the sign-in flow.
        // See below.
    }

    Java

    Task<AuthResult> pendingResultTask = firebaseAuth.getPendingAuthResult();
    if (pendingResultTask != null) {
        // There's something already here! Finish the sign-in for your user.
        pendingResultTask
                .addOnSuccessListener(
                        new OnSuccessListener<AuthResult>() {
                            @Override
                            public void onSuccess(AuthResult authResult) {
                                // User is signed in.
                                // IdP data available in
                                // authResult.getAdditionalUserInfo().getProfile().
                                // The OAuth access token can also be retrieved:
                                // ((OAuthCredential)authResult.getCredential()).getAccessToken().
                                // The OAuth secret can be retrieved by calling:
                                // ((OAuthCredential)authResult.getCredential()).getSecret().
                            }
                        })
                .addOnFailureListener(
                        new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                // Handle failure.
                            }
                        });
    } else {
        // There's no pending result so you need to start the sign-in flow.
        // See below.
    }

    لبدء مسار تسجيل الدخول، استخدِم startActivityForSignInWithProvider:

    Kotlin

    firebaseAuth
        .startActivityForSignInWithProvider(activity, provider.build())
        .addOnSuccessListener {
            // User is signed in.
            // IdP data available in
            // authResult.getAdditionalUserInfo().getProfile().
            // The OAuth access token can also be retrieved:
            // ((OAuthCredential)authResult.getCredential()).getAccessToken().
            // The OAuth secret can be retrieved by calling:
            // ((OAuthCredential)authResult.getCredential()).getSecret().
        }
        .addOnFailureListener {
            // Handle failure.
        }

    Java

    firebaseAuth
            .startActivityForSignInWithProvider(/* activity= */ this, provider.build())
            .addOnSuccessListener(
                    new OnSuccessListener<AuthResult>() {
                        @Override
                        public void onSuccess(AuthResult authResult) {
                            // User is signed in.
                            // IdP data available in
                            // authResult.getAdditionalUserInfo().getProfile().
                            // The OAuth access token can also be retrieved:
                            // ((OAuthCredential)authResult.getCredential()).getAccessToken().
                            // The OAuth secret can be retrieved by calling:
                            // ((OAuthCredential)authResult.getCredential()).getSecret().
                        }
                    })
            .addOnFailureListener(
                    new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            // Handle failure.
                        }
                    });

  5. في حين أنّ الأمثلة أعلاه تركّز على مسارات تسجيل الدخول، يمكنك أيضًا ربط موفّر OIDC بمستخدم حالي باستخدام startActivityForLinkWithProvider. على سبيل المثال، يمكنك ربط عدّة موفّرين بالمستخدم نفسه، ما يسمح له بتسجيل الدخول باستخدام أيّ منهما.

    Kotlin

    // The user is already signed-in.
    val firebaseUser = firebaseAuth.currentUser!!
    firebaseUser
        .startActivityForLinkWithProvider(activity, provider.build())
        .addOnSuccessListener {
            // Provider credential is linked to the current user.
            // IdP data available in
            // authResult.getAdditionalUserInfo().getProfile().
            // The OAuth access token can also be retrieved:
            // authResult.getCredential().getAccessToken().
            // The OAuth secret can be retrieved by calling:
            // authResult.getCredential().getSecret().
        }
        .addOnFailureListener {
            // Handle failure.
        }

    Java

    // The user is already signed-in.
    FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
    
    firebaseUser
            .startActivityForLinkWithProvider(/* activity= */ this, provider.build())
            .addOnSuccessListener(
                    new OnSuccessListener<AuthResult>() {
                        @Override
                        public void onSuccess(AuthResult authResult) {
                            // Provider credential is linked to the current user.
                            // IdP data available in
                            // authResult.getAdditionalUserInfo().getProfile().
                            // The OAuth access token can also be retrieved:
                            // authResult.getCredential().getAccessToken().
                            // The OAuth secret can be retrieved by calling:
                            // authResult.getCredential().getSecret().
                        }
                    })
            .addOnFailureListener(
                    new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            // Handle failure.
                        }
                    });

  6. يمكن استخدام النمط نفسه مع startActivityForReauthenticateWithProvider الذي يمكن استخدامه لاسترداد بيانات اعتماد جديدة للعمليات الحسّاسة التي تتطلّب تسجيل دخول حديثًا.

    Kotlin

    // The user is already signed-in.
    val firebaseUser = firebaseAuth.currentUser!!
    firebaseUser
        .startActivityForReauthenticateWithProvider(activity, provider.build())
        .addOnSuccessListener {
            // User is re-authenticated with fresh tokens and
            // should be able to perform sensitive operations
            // like account deletion and email or password
            // update.
        }
        .addOnFailureListener {
            // Handle failure.
        }

    Java

    // The user is already signed-in.
    FirebaseUser firebaseUser = firebaseAuth.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.
                        }
                    });

التعامل مع مسار تسجيل الدخول يدويًا

إذا سبق لك تنفيذ مسار تسجيل الدخول باستخدام OpenID Connect في تطبيقك، يمكنك استخدام رمز التعريف مباشرةً للمصادقة باستخدام Firebase:

Kotlin

val providerId = "oidc.example-provider" // As registered in Firebase console.
val credential = oAuthCredential(providerId) {
    setIdToken(idToken) // ID token from OpenID Connect flow.
}
Firebase.auth
    .signInWithCredential(credential)
    .addOnSuccessListener { authResult ->
        // User is signed in.

        // IdP data available in:
        //    authResult.additionalUserInfo.profile
    }
    .addOnFailureListener { e ->
        // Handle failure.
    }

Java

AuthCredential credential = OAuthProvider
        .newCredentialBuilder("oidc.example-provider")  // As registered in Firebase console.
        .setIdToken(idToken)  // ID token from OpenID Connect flow.
        .build();
FirebaseAuth.getInstance()
        .signInWithCredential(credential)
        .addOnSuccessListener(new OnSuccessListener<AuthResult>() {
            @Override
            public void onSuccess(AuthResult authResult) {
                // User is signed in.

                // IdP data available in:
                //    authResult.getAdditionalUserInfo().getProfile()
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // Handle failure.
            }
        });

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

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

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

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

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

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

Kotlin

Firebase.auth.signOut()

Java

FirebaseAuth.getInstance().signOut();