13
votes

Flutter: Comment écouter FirebaseUser est un booléen vérifié par e-mail?

Mon idée: je souhaite utiliser le plug-in d'authentification Firebase dans Flutter pour enregistrer les utilisateurs. Mais avant de pouvoir accéder à l'application, ils doivent vérifier leur adresse e-mail. C'est pourquoi je pousse les utilisateurs de Firebase après l'enregistrement vers un écran de vérification. Ceci est juste un écran de chargement qui indique à l'utilisateur qu'il doit vérifier son email.

Mais maintenant: comment puis-je écouter en continu, si l'email des utilisateurs est vérifié ou non et l'envoyer (quand c'est vrai) à l'écran d'accueil?

Je suis nouveau sur Flutter et je ne sais pas si je dois utiliser un Streams ou Observables ou un while Loop ou setState () ou autre chose pour une telle vérification booléenne. Et je ne sais pas non plus comment mettre en place une solution.

Voici mon code de base pour enregistrer un utilisateur:

     if (user.isEmailVerified == true) {
        
        //go to Homescreen
        return true; 
      } else {

        //show verification screen(loading spinner)
        return false;
      }

J'ai essayé ceci:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';

class AuthService {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  final Firestore _db = Firestore.instance;

  Future<FirebaseUser> get getUser => _auth.currentUser();

  Stream<FirebaseUser> get user => _auth.onAuthStateChanged;

  Future<FirebaseUser> edubslogin(String email, String password) async {
    try {
      final FirebaseUser user = await _auth.createUserWithEmailAndPassword(
        email: email,
        password: password,
      );
     
      await user.sendEmailVerification();
      
      //email verification somewhere here
    
      updateUserData(user);
      return user;
    } catch (error) {
      print(error);
      return null;
    }
  }

Mais je n'obtiens pas de valeur booléenne true de isEmailVerified .

Qu'est-ce que je dois faire?


0 commentaires

7 Réponses :


10
votes

Cette vérification n'est pas aussi simple que vous l'espériez. Premièrement, il y a le problème de reconnaître que l'utilisateur a vérifié son courrier électronique. Deuxièmement, il y a le problème qu'il n'y a aucune sorte de notification que vous pouvez écouter qui déclenchera automatiquement un changement dans votre application.

Consultez ce fil pour plus d'informations sur l'e-mailVérifié: https://github.com/flutter/flutter/issues/20390#issuecomment-514411392

Je n'ai pu vérifier l'utilisateur que si j'ai 1) créé son compte, 2) je l'ai connecté, 3) puis vérifié pour m'assurer qu'il a vérifié son adresse e-mail.

final FirebaseAuth _auth = FirebaseAuth.instance;

var _authenticatedUser = await _auth.signInWithEmailAndPassword(email: _email, password: _password); 

//where _email and _password were simply what the user typed in the textfields.



if (_authenticatedUser.isEmailVerified) {
        //Verified
      } else {
        //Not verified
        }

Partie 2: Comment faire pour que votre application reconnaisse que l'utilisateur a confirmé son e-mail? Trouvez un moyen de déclencher la fonction qui vérifie la confirmation. Un bouton serait assez simple. Si vous voulez qu'il voit "automatique", je suppose que vous pouvez créer un minuteur qui vérifie la vérification des e-mails toutes les 10 secondes environ.


2 commentaires

La clé ici est que l'application ne reçoit pas automatiquement de notification lorsque l'utilisateur a vérifié son adresse e-mail, vous devrez donc le vérifier vous-même à partir de l'application. Pour ce faire, vous forceriez un reload du profil utilisateur, de sorte que vous obteniez les dernières valeurs du serveur. Avec ceux-ci, vous pouvez ensuite revérifier la valeur de isEmailVerified .


"This verification isn't as straightforward as you'd hope" Elle est aussi simple que possible.



1
votes

J'ai trouvé un moyen en mettant à jour le profil utilisateur firebase et en l'appelant dans init() comme la fonction ci-dessous.

void _checkEmailVerification() async {
    await widget.auth.getCurrentUser().then((user) {
      UserUpdateInfo userUpdateInfo = new UserUpdateInfo();
      userUpdateInfo.displayName = user.displayName;
      user.updateProfile(userUpdateInfo).then((onValue) {
        setState(() {
          _isEmailVerified = user.isEmailVerified;
        });
      });
    });
  }


0 commentaires

14
votes

Je viens de faire face à la même situation dans mon application. Ma solution était de créer une minuterie périodique dans la méthode initState d'une route stratégique pour contenir l'application jusqu'à ce que l'e-mail soit vérifié. Ce n'est pas aussi élégant que d'utiliser un auditeur mais fonctionne très bien.

bool _isUserEmailVerified;
Timer _timer;

@override
void initState() {
    super.initState();
    // ... any code here ...
    Future(() async {
        _timer = Timer.periodic(Duration(seconds: 5), (timer) async {
            await FirebaseAuth.instance.currentUser()..reload();
            var user = await FirebaseAuth.instance.currentUser();
            if (user.isEmailVerified) {
                setState((){
                    _isUserEmailVerified = user.isEmailVerified;
                });
                timer.cancel();
            }
        });
    });
}

@override
void dispose() {
    super.dispose();
    if (_timer != null) {
        _timer.cancel();
    }
}


2 commentaires

C'est génial! Merci!


import 'dart:async';



1
votes

Eh bien, j'ai créé un flux pour gérer cela. Pas si élégant mais fonctionne. Utilisez un StreamProvider.value () pour gérer les événements.

  Stream<userVerificationStatus> checkUserVerified() async* {
    bool verified = false;
    yield userVerificationStatus(status: Status.LOADING); 
    while (!verified) {
      await Future.delayed(Duration(seconds: 5));
      FirebaseUser user = await _auth.currentUser();
      if(user!=null)await user.reload();
      if (user == null) {
        yield userVerificationStatus(status: Status.NULL);
      } else {
        print("isemailverified ${user.isEmailVerified}");
        await user.reload();
        verified = user.isEmailVerified;
        if(verified)
        yield userVerificationStatus(status: Status.VERIFIED);
        else
        yield userVerificationStatus(status: Status.NOT_VERIFIED);
      }
    }
  }


1 commentaires

_auth doit être FirebaseAuth.Instance et userVerificationStatus n'est qu'une classe d'énumération personnalisée



0
votes

Étant authOnChanged que authOnChanged n'écoute que les actions de connexion et de authOnChanged , dans votre méthode de connexion, déconnectez-vous d'abord, puis essayez de vous connecter.

await _firebaseAuth.signOut();

authResult = await _firebaseAuth.signInWithEmailAndPassword(email: email, password: password);

return authResult.user;

Dans onAuthChanged , lorsque vous contrôlez si user.isEmailVerified , cela fonctionnera puisque vous vous êtes déconnecté et il mettra à jour l'utilisateur même si vous ne vous êtes pas encore connecté, car la déconnexion déclenchera votre onAuthChanged même si vous ne vous êtes pas connecté .

C'est comme tricher, mais la seule façon que j'ai trouvée sans délai est la suivante.


0 commentaires

2
votes

Pour que l'application reconnaisse si l'utilisateur a vérifié son e-mail, vous pouvez y parvenir avec un simple user.reload .

Pour le tester vous-même, implémentez un bouton avec le code onPressed:

 FlatButton(
    child: Text("check"),
    textColor: Colors.white,
    onPressed: () async {
    try {
      FirebaseUser user = await _firebaseAuth.currentUser();
      await user.reload();
      user = await _firebaseAuth.currentUser();
        print( user.isEmailVerified); 
        

     } catch (e) {
      return e.message;
    }
}),


0 commentaires

0
votes

L'écouteur de changement d'état d'authentification n'a pas fonctionné pour moi. Le champ isEmailVerified reste false même après que l'utilisateur a vérifié son e-mail.

Ma solution de contournement: à partir de l'hypothèse que l'utilisateur quitte l'application pour vérifier son courrier électronique (ce qui signifie que l'application est en pause ), et il revient à l'application après l'avoir vérifiée (l'application reprend ).

Ce que j'ai fait, c'est de joindre un WidgetsBinding à un widget avec état pertinent que je voulais afficher si l'e-mail était vérifié (mais peut être fait ailleurs). Cela implique deux étapes.

La première étape consiste à attacher la liaison:

  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed && !firebaseUser.isEmailVerified)
      refreshFirebaseUser().then((value) => setState(() {}));
    super.didChangeAppLifecycleState(state);
  }
  Future<void> refreshFirebaseUser() async {
    await firebaseUser.reload();
    firebaseUser = FirebaseAuth.instance.currentUser;
  }

La deuxième étape consiste à remplacer didChangeAppLifecycleState pour recharger l'utilisateur. J'ai créé une fonction qui fait le rechargement et définit un nouvel objet firebaseUser

  @override
  void initState() {
    WidgetsBinding.instance.addObserver(this);
    super.initState();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

Donc, ce que cela fait essentiellement est de recharger l'objet utilisateur Firebase à chaque fois que l'utilisateur revient dans l'application, alors que son e-mail n'est pas vérifié. J'ai choisi cette solution plutôt que de régler et d'annuler une minuterie, car elle évitait de définir une action récurrente via une minuterie qui pourrait être excessive pour ce problème particulier.


0 commentaires