اصالت‌سنجی بااستفاده از OpenID Connect در Android

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

قبل از شروع

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

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

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

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

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

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

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

  3. در کنسول Firebase، به امنیت > اصالت‌سنجی بروید.

  4. در برگه روش ورود به سیستم، روی افزودن ارائه‌دهنده جدید کلیک کنید، و سپس روی OpenID Connect کلیک کنید.

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

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

  6. نامی برای این ارائه‌دهنده انتخاب کنید. شناسه ارائه‌دهنده تولیدشده را یادداشت کنید: چیزی شبیه oidc.example-provider. وقتی کد ورود به سیستم را به برنامه‌تان اضافه می‌کنید به این شناسه نیاز خواهید داشت.

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

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

مدیریت جریان ورود به سیستم با «کیت توسعه نرم‌افزار Firebase»

اگر درحال ساختن برنامه Android هستید، ساده‌ترین راه برای اصالت‌سنجی کاربران با Firebase بااستفاده از ارائه‌دهنده OIDC شما این است که کل جریان ورود به سیستم را با کیت توسعه نرم‌افزار Firebase Android مدیریت کنید.

برای مدیریت جریان ورود به سیستم با «کیت توسعه نرم‌افزار Firebase Android»، این مراحل را دنبال کنید:

  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، این عملیات با بالا آوردن برگه سفارشی 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. اگرچه مثال‌های بالا بر جریان‌های ورود به سیستم تمرکز دارند، شما همچنین می‌توانید بااستفاده از 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 شیء دریافت کنید. مدیریت کاربران را ببینید.

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

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

برای خروج از سیستم کاربر، signOut را فراخوانی کنید:

Kotlin

Firebase.auth.signOut()

Java

FirebaseAuth.getInstance().signOut();