احراز هویت با استفاده از OpenID Connect در Android

اگر به Firebase Authentication with Identity Platform ارتقا داده‌اید، می‌توانید کاربران خود را با Firebase و با استفاده از ارائه‌دهنده‌ی سازگار با OpenID Connect (OIDC) مورد نظر خود، احراز هویت کنید. این امر امکان استفاده از ارائه‌دهندگان هویتی را که به طور بومی توسط Firebase پشتیبانی نمی‌شوند، فراهم می‌کند.

قبل از اینکه شروع کنی

برای ورود کاربران با استفاده از ارائه‌دهنده OIDC، ابتدا باید اطلاعاتی را از ارائه‌دهنده جمع‌آوری کنید:

  • شناسه مشتری : رشته‌ای منحصر به فرد برای ارائه‌دهنده که برنامه شما را شناسایی می‌کند. ارائه‌دهنده شما ممکن است برای هر پلتفرمی که پشتیبانی می‌کنید، شناسه مشتری متفاوتی به شما اختصاص دهد. این یکی از مقادیر ادعای aud در توکن‌های شناسه صادر شده توسط ارائه‌دهنده شما است.

  • رمز کلاینت : یک رشته مخفی که ارائه دهنده برای تأیید مالکیت شناسه کلاینت از آن استفاده می‌کند. برای هر شناسه کلاینت، به یک رمز کلاینت منطبق نیاز خواهید داشت. (این مقدار فقط در صورتی لازم است که از جریان کد احراز هویت استفاده می‌کنید، که اکیداً توصیه می‌شود.)

  • صادرکننده : رشته‌ای که ارائه‌دهنده شما را شناسایی می‌کند. این مقدار باید یک URL باشد که وقتی با /.well-known/openid-configuration اضافه می‌شود، محل سند کشف OIDC ارائه‌دهنده باشد. برای مثال، اگر صادرکننده https://auth.example.com باشد، سند کشف باید در https://auth.example.com/.well-known/openid-configuration در دسترس باشد.

پس از اینکه اطلاعات فوق را در اختیار داشتید، OpenID Connect را به عنوان ارائه دهنده ورود به سیستم برای پروژه Firebase خود فعال کنید:

  1. فایربیس را به پروژه اندروید خود اضافه کنید .

  2. اگر به Firebase Authentication with Identity Platform ارتقا نداده‌اید، این کار را انجام دهید. احراز هویت OpenID Connect فقط در پروژه‌های ارتقا یافته در دسترس است.

  3. در صفحه ارائه دهندگان ورود به سیستم کنسول Firebase ، روی افزودن ارائه دهنده جدید کلیک کنید و سپس روی OpenID Connect کلیک کنید.

  4. انتخاب کنید که آیا از جریان کد مجوز یا جریان اعطای ضمنی استفاده خواهید کرد.

    اگر ارائه‌دهنده شما از جریان کد پشتیبانی می‌کند، همیشه باید از آن استفاده کنید . جریان ضمنی امنیت کمتری دارد و استفاده از آن اکیداً توصیه نمی‌شود.

  5. به این ارائه‌دهنده یک نام بدهید. به شناسه ارائه‌دهنده‌ای که ایجاد می‌شود توجه کنید: چیزی شبیه به oidc.example-provider . هنگام افزودن کد ورود به برنامه خود به این شناسه نیاز خواهید داشت.

  6. شناسه مشتری و رمز مشتری و رشته صادرکننده ارائه دهنده خود را مشخص کنید. این مقادیر باید دقیقاً با مقادیری که ارائه دهنده شما به شما اختصاص داده است، مطابقت داشته باشند.

  7. تغییرات خود را ذخیره کنید.

مدیریت جریان ورود به سیستم با Firebase SDK

اگر در حال ساخت یک برنامه اندروید هستید، ساده‌ترین راه برای احراز هویت کاربران با 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. با استفاده از شیء ارائه دهنده OAuth، با Firebase احراز هویت کنید. توجه داشته باشید که برخلاف سایر عملیات FirebaseAuth، این عملیات با نمایش یک تب سفارشی کروم ، کنترل رابط کاربری شما را به دست می‌گیرد. در نتیجه، به Activity خود در OnSuccessListener و OnFailureListener که پیوست می‌کنید، ارجاع ندهید زیرا آنها بلافاصله پس از شروع عملیات رابط کاربری جدا می‌شوند.

    ابتدا باید بررسی کنید که آیا قبلاً پاسخی دریافت کرده‌اید یا خیر. ورود به سیستم با این روش، Activity شما را در پس‌زمینه قرار می‌دهد، به این معنی که سیستم می‌تواند در طول جریان ورود، آن را بازیابی کند. برای اطمینان از اینکه در صورت بروز این اتفاق، کاربر را مجبور به تلاش مجدد نکنید، باید بررسی کنید که آیا نتیجه‌ای از قبل وجود دارد یا خیر.

    برای بررسی اینکه آیا نتیجه‌ای در انتظار است یا خیر، 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. در حالی که مثال‌های بالا بر جریان‌های ورود به سیستم تمرکز دارند، شما همچنین می‌توانید با استفاده از startActivityForLinkWithProvider ، یک ارائه‌دهنده OIDC را به یک کاربر موجود پیوند دهید. به عنوان مثال، می‌توانید چندین ارائه‌دهنده را به یک کاربر پیوند دهید و به آنها اجازه دهید با هر یک از آنها وارد سیستم شوند.

    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 را در برنامه خود پیاده‌سازی کرده‌اید، می‌توانید مستقیماً از توکن ID برای تأیید اعتبار با 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 دریافت کنید. به مدیریت کاربران مراجعه کنید.

  • در قوانین امنیتی پایگاه داده و Cloud Storage Firebase Realtime Database ، می‌توانید شناسه کاربری منحصر به فرد کاربر وارد شده را از متغیر auth دریافت کنید و از آن برای کنترل داده‌هایی که کاربر می‌تواند به آنها دسترسی داشته باشد، استفاده کنید.

شما می‌توانید با پیوند دادن اعتبارنامه‌های ارائه‌دهنده‌ی احراز هویت به یک حساب کاربری موجود، به کاربران اجازه دهید با استفاده از چندین ارائه‌دهنده‌ی احراز هویت به برنامه‌ی شما وارد شوند.

برای خروج کاربر، signOut را فراخوانی کنید:

Kotlin

Firebase.auth.signOut()

Java

FirebaseAuth.getInstance().signOut();