Flutter: How to listen to the FirebaseUser is Email verified boolean?

后端 未结 8 680
走了就别回头了
走了就别回头了 2021-01-01 20:38

My Idea: I want to use the Firebase Auth Plugin in Flutter to register the users. But before they can access the App, they have to verify their Email addres

相关标签:
8条回答
  • 2021-01-01 21:06

    I have found a way by updating firebase user profile and calling it in init() like below function.

    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 讨论(0)
  • 2021-01-01 21:06

    Since authOnChanged only listens for sign in and sign out actions, in your sign in method, first sign out then try to sign in.

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

    In the onAuthChanged, when you control if user.isEmailVerified, it will work since you have signed out and it will update the user even if you haven't signed in yet because sign out will trigger your onAuthChanged even if you haven't signed in.

    It is like cheating but the only way that I have found without timeout is this.

    0 讨论(0)
  • 2021-01-01 21:09

    Auth state change listener didn't work for me. Field isEmailVerified remains false even after user verifies his email.

    My workaround: Started from the assumption that user leaves the app to verify his email (which mean app is paused), and he returns to the app after verifying it (app resumes).

    What I did was attach a WidgetsBinding to a relevant stateful widget where I wanted to display if email was verified (but can be done elsewhere). This involves two steps.

    First step is to attach the binding:

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

    Second step is to override the didChangeAppLifecycleState to reload the user. I created a function that does the reload and sets a new firebaseUser object

      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;
      }
    

    So what this is basically doing is to reload firebase user object everytime the user returns to the app, while its email is not verified. I chose this solution over setting and cancelling a timer as it avoided setting a recurrent action through a timer which could be overkill for this particular problem.

    0 讨论(0)
  • 2021-01-01 21:12

    In order for the app to recognise if the user has verified their email you can achieve this with a simple user.reload.

    In order to test it yourself implement a button with onPressed code:

     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 讨论(0)
  • 2021-01-01 21:13

    True. None of the FirebaseAuth idTokenChanges() , authStateChanges() or userChanges() will send you an event if the user verifies their email. I'm using a combination of the methods to get an email verification update in my app and it seems to be working well.

    First I check the status in the initState() method and start a timer if email is not verified

      @override
      void initState() {
        super.initState();
        WidgetsBinding.instance.addObserver(this);
    
        //Get Authenticated user
        user = context.read<AuthenticationService>().currentUser();
        _isEmailVerified = user.emailVerified;
        if (!_isEmailVerified) _startEmailVerificationTimer();
    
        }
    

    I also listen for app background/foreground events in case the user happens to leave the app to confirm their email ( If you also do this, add WidgetsBindingObserver to your class)

     @override
      void didChangeAppLifecycleState(AppLifecycleState state) {
        if (state == AppLifecycleState.resumed) {
          user = context.read<AuthenticationService>().reloadCurrentUser();
          if (user.emailVerified) {
            setState(() {
              _isEmailVerified = user.emailVerified;
            });
            timer?.cancel();
          } else {
            if (!timer.isActive) _startEmailVerificationTimer();
          }
        } 
      }
    

    This is the _startEmailVerificationTimer() method

     _startEmailVerificationTimer() {
        timer = Timer.periodic(Duration(seconds: 5), (Timer _) {
          user = context.read<AuthenticationService>().reloadCurrentUser();
          if (user.emailVerified) {
            setState(() {
              _isEmailVerified = user.emailVerified;
            });
            timer.cancel();
          }
        });
      }
    

    Don't forget to dispose the timer

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

    My Firebase User methods in case anyone is interested:

      User currentUser() {
        return _firebaseAuth.currentUser;
      }
    
      User reloadCurrentUser() {
        User oldUser = _firebaseAuth.currentUser;
        oldUser.reload();
        User newUser = _firebaseAuth.currentUser;
        return newUser;
      }
    
    0 讨论(0)
  • 2021-01-01 21:24

    Well I created a stream to handle this. Not so elegant but works. Use a StreamProvider.value() to handle events.

      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);
          }
        }
      }
    
    0 讨论(0)
提交回复
热议问题