【问题标题】:Check if user exists on FIrestore检查用户是否存在于 FIrestore
【发布时间】:2019-11-06 16:54:13
【问题描述】:

我有这个使用 SignInWithGogle 来登录/注册用户的功能

 void _signInWithGoogle() async {
    final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
    final GoogleSignInAuthentication googleAuth =
        await googleUser.authentication;
    final AuthCredential credential = GoogleAuthProvider.getCredential(
      accessToken: googleAuth.accessToken,
      idToken: googleAuth.idToken,
    );
    final FirebaseUser user = (await _auth.signInWithCredential(credential)).user;
    assert(user.email != null);
    assert(user.displayName != null);
    assert(!user.isAnonymous);
    assert(await user.getIdToken() != null);

    final FirebaseUser currentUser = await _auth.currentUser();
    assert(user.uid == currentUser.uid);
    print('user email here $user.email');
    setState(() {
      if (user != null) {
        _success = true;
        _userID = user.uid;
        final userToSubmit = User(
            email: user.email,
            id: user.uid,
            name: user.displayName,
            owner: false,
            favorites: null);
        print('USER ID USER ID USER ID ${user.uid}');
        DocumentReference dbRef =
            Firestore.instance.collection('users').document(user.uid);
        dbRef.get().then((value) {
          print('VALUE EXISTS? ${value.exists} y VALUE $value');
          value.exists ?
            _goToHomeScreen(user)
          :
          dbRef
              .collection('prf')
              .document('profile')
              .setData(userToSubmit.toJson())
              .then(_goToHomeScreen(user));
        });
      } else {
        _success = false;
      }
    });
  }

问题是,当用户注销然后登录时,它会设置新数据,并且用户丢失了他们拥有的所有东西,比如收藏夹等等......我认为检查文档是否存在应该可以解决问题,但尽管文档是否存在返回 false。 这就是我说的这段代码

DocumentReference dbRef =
                Firestore.instance.collection('users').document(user.uid);
            dbRef.get().then((value) {
              print('VALUE EXISTS? ${value.exists} y VALUE $value');
              value.exists ?
                _goToHomeScreen(user)
              :
              dbRef
                  .collection('prf')
                  .document('profile')
                  .setData(userToSubmit.toJson())
                  .then(_goToHomeScreen(user));
            });
          }

为什么即使 user.uid 和文档存在,它也会返回 false?我做错了什么?

【问题讨论】:

  • 为什么要投反对票?!?

标签: firebase flutter dart google-cloud-firestore


【解决方案1】:

我实现的最终解决方案是这样的:

 FirebaseUser firebaseUser;
    try {
      firebaseUser = (await FirebaseAuth.instance.signInWithCredential(credential)).user;
    } catch(e) {
      print(e.toString());
    } finally {
      final userToSubmit = User(
          email: firebaseUser.email,
          id: firebaseUser.uid,
          name: firebaseUser.displayName,
          owner: false,
          restauranteAdded: false);
      DocumentReference dbRef =
      Firestore.instance.collection('users').document(firebaseUser.uid).collection('nameOfTheCollection').document('documentName');

      dbRef.get().then((data) {
        data.exists ? _goToHomeScreen(user) :  
          _createUser();
      });

这样我检查用户文档是否存在于我的 Firestore 数据库中,如果不存在,它会创建它。

【讨论】:

  • 您不认为这会增加 Firebase 的读取次数吗?就像每次用户尝试通过 Google 登录一样,您必须检查该用户是否在 Firestore 集合中可用,这反过来会影响读取计数,对吗?
  • 只有在创建新用户时才会使用它。因此,如果算上规则检查,它只会额外阅读 1 次,好吧 2 次。
  • 知道了。谢谢!
【解决方案2】:

发生了很多事情。通常,您不会使用 setState() 方法更新任何 state 对象。 setState 用于告诉小部件某些 state 已更改 - 它与更改同步调用 ,但在这里您只是检查文档是否存在并且什么都没有变了,没必要。

此外,您实际上根本没有返回user 对象,因此我阅读的这段代码将始终返回false

  1. 您应该在此处完全删除 setState(您正在执行的操作不需要)
  2. 运行一个登录方法,该方法返回您想要使用的用户对象。
  3. 一旦您知道您有一个登录用户(即 w/ 登录用户的 uid)访问您的数据库

这是一个尝试的选项:

//Create a User class so that you don't have to call FireBase in your methods.
class User {
  User({
    @required this.uid,
    this.email,
    this.displayName,
  });
  final String uid;
  final String email;//these are whatever you want
  final String displayName;
}

//put sign in methods into an abstract class. Don't have to, but keeps code flexible if you don't stay with firebase
abstract class AuthBase {
 //add in other signin methods as needed
  Future<User> signInWithGoogle();

}

//Implement AuthBase in class Auth
class Auth implements AuthBase {
  final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;

//Get a User from Firebase User
  User _userFromFirebase(FirebaseUser user) {
    if (user == null) {
      return null;
    }
    return User(
      uid: user.uid,
      displayName: user.displayName,
      email: user.email,
    );
  }

//your signinWithGoogle method
Future<User> signInWithGoogle() async {
  //where User is the class you've created
  GoogleSignIn googleSignIn = GoogleSignIn();
  GoogleSignInAccount googleUser = await googleSignIn.signIn();

  if (googleUser != null) {
    GoogleSignInAuthentication googleAuth = await googleUser.authentication;
    if (googleAuth.idToken != null && googleAuth.accessToken != null) {
      final authResult = await _firebaseAuth.signInWithCredential( //await your instance of FirebaseAuth
        GoogleAuthProvider.getCredential(
          idToken: googleAuth.idToken,
          accessToken: googleAuth.accessToken,
        ),
      );

      return _userFromFirebase(authResult.user); //your signed in firebase user that you can do stuff with uid, email, displayname, etc.
    } else {
      throw PlatformException(
        code: 'ERROR_MISSING_GOOGLE_AUTH_TOKEN',
        message: '',
      );
    }
  } else {
    throw PlatformException(
      code: 'ERROR_ABORTED_BY_USER',
      message: '',
    );
  }
}

【讨论】:

  • 好吧,这段代码确实返回了一个用户对象,它只是一段代码,它工作正常,但你对 setState 是正确的,应该隔离 dbRef 逻辑。但是问题是关于如何检查数据库中是否存在文档 ID。
  • 好的。我试图解决您为什么返回“false”,这是问题的最后一部分。
  • 行 print('USER ID USER ID USER ID ${user.uid}');返回用户 ID,所以就像我说的问题不在于身份验证流程。但是我找到了一种方法来检查文档 ID 是否存在。
猜你喜欢
  • 2018-03-16
  • 2018-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-21
相关资源
最近更新 更多