DéveloppeurWeb.Com
    DéveloppeurWeb.Com
    • Agile Zone
    • AI Zone
    • Cloud Zone
    • Database Zone
    • DevOps Zone
    • Integration Zone
    • Web Dev Zone
    DéveloppeurWeb.Com
    Home»Uncategorized»Flux de connexion avec Google Identity Services et Firebase
    Uncategorized

    Flux de connexion avec Google Identity Services et Firebase

    mars 1, 2023
    Flux de connexion avec Google Identity Services et Firebase
    Share
    Facebook Twitter Pinterest Reddit WhatsApp Email

    La plupart des applications ont une sorte d’authentification. Pour cet article, nous verrons comment ce flux fonctionne en utilisant la connexion One Tap de Google, Firebase et Amity.

    La pile technologique que nous utiliserons est :

    • Script Kotlin (KTS) pour notre Gradle
    • Jetpack Compose pour notre interface utilisateur
    • Architecture MVVM
    • Poignée pour l’injection de dépendance
    • SDK social d’Amity
    • Authentification OneTap de Google
    • Authentification Firebase

    Le déroulement est le suivant : premièrement, nous vérifions si la session d’Amity est valide ; si c’est le cas, nous continuerons avec notre flux principal ; sinon, nous redirigerons nos utilisateurs vers notre écran de connexion. Là, nous essaierons d’abord de connecter nos utilisateurs à l’aide de Google. S’ils se sont déjà connectés à notre application, cela réussira, et nous pourrons alors nous connecter à l’aide de Firebase. Sinon, nous devons d’abord inscrire nos utilisateurs à notre application, puis continuer avec Firebase.

    Configuration

    Bon, commençons ! Tout d’abord, pour configurer notre projet, nous allons utiliser le guide officiel. Puisque nous n’utilisons pas Groovy, les dépendances sont ajoutées, comme indiqué ci-dessous.

    plugins {
        ...
        id("com.google.gms.google-services") version "4.3.14"
    }
    
    dependencies {
        ...
        implementation("com.google.android.gms:play-services-auth:20.4.0")
    }
    
    apply(plugin = "com.google.gms.google-services")

    * Alors que vous devez utiliser le fourni libs.versions file (catalogue des versions), pour des raisons de lisibilité du code, dans cet article, nous ajouterons les versions comme celle-ci.

    Puisque nous sommes ici, nous ajouterons également les dépendances Amity et Firebase dont nous aurons besoin plus tard. Malheureusement, l’ajout de dépendances Firebase dans le modèle ne peut pas encore être effectué via l’assistant d’Android Studio sans lever d’exceptions, nous allons donc les ajouter manuellement.

    dependencies {   
        ... 
    
        // Amity
        implementation("com.github.AmityCo.Amity-Social-Cloud-SDK-Android:amity-sdk:5.33.2")
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-rx2:1.6.4")
    
        // Firebase
        implementation(platform("com.google.firebase:firebase-bom:31.1.1"))
        implementation("com.google.firebase:firebase-analytics-ktx")
        implementation("com.google.firebase:firebase-auth-ktx")
        implementation("com.google.android.gms:play-services-auth:20.4.0")
        implementation("com.google.firebase:firebase-firestore-ktx")
    }

    Notre dernière étape consiste à configurer notre console Firebase. Selon la documentation officielle :

    Pour utiliser un fournisseur d’authentification, vous devez l’activer dans la console Firebase. Accédez à la page Méthode de connexion dans la section Authentification Firebase pour activer la connexion par e-mail/mot de passe et tout autre fournisseur d’identité que vous souhaitez pour votre application.

    Nous allons bien sûr activer la connexion Google. Ensuite, nous allons accéder aux paramètres du projet et ajouter notre empreinte digitale de certificat SHA.

    Nous sommes maintenant prêts à commencer à ajouter notre code de connexion ! Nous créons d’abord les fichiers dont nous aurons besoin : MainNavigation, MainViewModel, LoginScreen, LoginViewModel, AuthRepository.

    Observation de l’état de l’authentification

    Notre premier Composable à s’appeler est le MainNavigation. Pour vérifier en permanence la validité de la session d’Amity, c’est ici que nous surveillerons son état. Puisque nous voulons que l’état de notre application reflète l’état de la session, nous allons le mapper à un StateFlow.

    StateFlow est un flux observable de détenteur d’état qui émet les mises à jour d’état actuelles et nouvelles à ses collecteurs. La valeur de l’état actuel peut également être lue via sa propriété value. Dans Android, StateFlow convient parfaitement aux classes qui doivent maintenir un état mutable observable.

    Nous initions et obtenons le SessionState dans le AuthRepository puis dans notre MainViewModel nous convertissons notre flow à un StateFlowet enfin, dans notre MainNavigation on l’observe.

    override val amitySession = flow {
            emit(AmityCoreClient.currentSessionState)
            AmityCoreClient.observeSessionState().asFlow()
        }

    val uiState: StateFlow<MainUiState> = authRepository
        .amitySession.map {
            when(it) {
                SessionState.NotLoggedIn,
                SessionState.Establishing -> MainUiState.LoggedOut
                SessionState.Established,
                SessionState.TokenExpired -> MainUiState.LoggedIn
                is SessionState.Terminated -> MainUiState.Banned
            }
        }
        .catch { Error(it) }
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), MainUiState.Loading) LaunchedEffect(lifecycleOwner) {
        viewModel.uiState.collect { state ->
            when(state) {
                MainUiState.Banned -> {} //TODO snackbar
                is MainUiState.Error -> {}  //TODO snackbar
                MainUiState.Loading -> { /* no-op */ }
                MainUiState.LoggedIn -> navController.navigate("main") { popUpTo(0) }
                MainUiState.LoggedOut -> navController.navigate("login") { popUpTo(0) }
            }
        }
    }

    LaunchedEffect(lifecycleOwner) {
        viewModel.uiState.collect { state ->
            when(state) {
                MainUiState.Banned -> showSnackbar(scope, snackbarHostState, userBannedText)
                is MainUiState.Error -> showSnackbar(scope, snackbarHostState, userErrorText)
                MainUiState.Loading -> { /* no-op */ }
                MainUiState.LoggedIn -> navController.navigate(Route.UsersList.route) { popUpTo(0) }
                MainUiState.LoggedOut -> navController.navigate(Route.Login.route) { popUpTo(0) }
            }
        }
    }

    Cool, maintenant nous pouvons observer l’état de nos utilisateurs !

    Connexion Google OneTap

    Nos utilisateurs voient maintenant notre page de connexion brillante, qui, pour l’instant, est simplement la suivante :

    @Composable
    fun LoginScreen(
        modifier: Modifier = Modifier,
        navigateToUsers: () -> Unit,
        viewModel: LoginViewModel = hiltViewModel()
    ) {
        Column(modifier) {
            Button(onClick = { /* TODO */ }) {
                Text(text = stringResource(R.string.login_google_bt))
            }
        }
    }

    Pas si brillant, après tout.

    Connexion Google amicale

    Pour commencer, nous avons besoin de notre appel de connexion dans notre AuthRepository. *

    * :

    Nous utilisons une interface pour encapsuler notre AuthRepository fonctions de. Cela sera particulièrement utile pour créer une maquette AuthRepository pour nos prochains tests.

    Notre signInRequest, SignUpRequest ainsi que les clients Firebase et Google sont fournis à nos AuthRepository mise en œuvre lors de l’injection de dépendance, comme indiqué ci-dessous :

    
    @Module
    @InstallIn(SingletonComponent::class)
    class AuthModule {
        private val signInRequest = BeginSignInRequest.builder()
            .setGoogleIdTokenRequestOptions(
                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
                    .setSupported(true)
                    .setServerClientId(BuildConfig.SERVER_CLIENT_ID)
                    // Only show accounts previously used to sign in.
                    .setFilterByAuthorizedAccounts(true)
                    .build())
            // Automatically sign in when exactly one credential is retrieved.
            .setAutoSelectEnabled(true)
            .build()
    
        private val signUpRequest = BeginSignInRequest.builder()
            .setGoogleIdTokenRequestOptions(
                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
                    .setSupported(true)
                    .setServerClientId(BuildConfig.SERVER_CLIENT_ID)
                    .setFilterByAuthorizedAccounts(false)
                    .build())
            .build()
    
        @Provides
        @Singleton
        fun provideAuthRepository(@ApplicationContext appContext: Context) : AuthRepository {
            return AuthRepositoryImp(
                Identity.getSignInClient(appContext),
                signInRequest,
                signUpRequest,
                Firebase.auth,
                Firebase.firestore
            )
        }
    }

    Retour à notre flux de connexion ! Comme mentionné ci-dessus, si c’est la première fois que nos utilisateurs tentent de se connecter avec ce compte, cela déclenchera une exception. Pour éviter d’afficher de faux messages d’erreur à l’utilisateur, lorsque nous recevons une exception dans notre méthode de connexion, nous essayons de nous inscrire. Si cela réussit, nous passons à autre chose ; sinon, nous traitons alors l’erreur.

    //AuthRepositoryImpl.kt
    
    override suspend fun signInWithGoogle(): OneTapResponse {
        return try {
            val result = oneTapClient.beginSignIn(signInRequest).await()
            ApiResponse.Success(result)
        } catch (e: Exception) {
            ApiResponse.Failure(e)
        }
    }
    
    override suspend fun signUpWithGoogle(): OneTapResponse {
        return try {
            val result = oneTapClient.beginSignIn(signUpRequest).await()
            ApiResponse.Success(result)
        } catch (e: Exception) {
            ApiResponse.Failure(e)
        }
    }

    Message d'erreur

    //LoginViewModel
    
    suspend fun googleSignIn(launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>) {
        when (val oneTapResponse: ApiResponse<BeginSignInResult> =
            authRepository.signInWithGoogle()) {
            is ApiResponse.Success -> {
                val result = oneTapResponse.data!!
                val intent = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()
                launcher.launch(intent)
            }
            is ApiResponse.Loading -> { /* no-op */ }
            else -> {
                // No saved credentials found. Launch the One Tap sign-up flow
                googleSignUp(launcher)
            }
        }
    }
    
    private suspend fun googleSignUp(launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>) {
        when(val oneTapResponse: ApiResponse<BeginSignInResult> = authRepository.signUpWithGoogle())  {
            is ApiResponse.Success -> {
                val result = oneTapResponse.data!!
                val intent = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()
                launcher.launch(intent)
            }
            is ApiResponse.Loading -> { /* no-op */ }
            else -> handleSignUpError()
        }
    }

    Si nous utilisions Views au lieu de Compose, nous gérerions le résultat de l’intention dans notre onActivityForResult méthode. Au lieu de cela, nous utiliserons le ManagedActivityResultLauncher dans notre LoginScreen. Si notre lanceur revient avec un résultat positif, nous obtiendrons alors l’identifiant de notre utilisateur et passerons à la connexion Firebase.

    @Composable
    fun LoginScreen(
        modifier: Modifier = Modifier,
        viewModel:...
    Share. Facebook Twitter Pinterest LinkedIn WhatsApp Reddit Email
    Add A Comment

    Leave A Reply Cancel Reply

    Catégories

    • Politique de cookies
    • Politique de confidentialité
    • CONTACT
    • Politique du DMCA
    • CONDITIONS D’UTILISATION
    • Avertissement
    © 2023 DéveloppeurWeb.Com.

    Type above and press Enter to search. Press Esc to cancel.