带有 Flutter 的 Firebase 中的唯一用户名

Posted

技术标签:

【中文标题】带有 Flutter 的 Firebase 中的唯一用户名【英文标题】:Unique username in Firebase with Flutter 【发布时间】:2020-02-06 06:24:19 【问题描述】:

我正在尝试为我的应用上的每个用户创建一个唯一的用户名。在注册时,我将该用户名值存储在一个单独的集合(“用户名”)中,因此当我检查用户名是否唯一时更容易通过它们,而不是通过每个用户及其字段。

在我的 signup.dart 我有一个文本字段验证器:

TextFormField(
  style: TextStyle(fontSize: 16.0, color: Colors.white),
  decoration: buildSignInInputDecoration("Username"),
  validator: (value) 
    if (value.length < 2 || value.isEmpty) 
      return "Username is too short.";
       else if (value.length > 12) 
        return "Username is too long.";
         else 
        return null;
        ,
        onSaved: (value) => _username = value.trim(),
        ),
  

我做了一个函数来检查用户名是否已经在集合中:(_username 是存储用户输入的字符串)

Future<bool> usernameCheck() async 
    final snapShot = await usernamesRef.document(_username).get();
    if (snapShot == null || !snapShot.exists) 
      return true; //username is unique.
     else 
      return false; //username exists.
    
  

我的问题是,我如何调用 usernameCheck 并使用我的验证器对其进行验证?提前致谢!

更新: 我实现了下面给出的答案,但不知何故,即使用户名不存在,valid 总是返回 false。

Future<bool> usernameCheck(String _username) async 
    final result =
        await usersRef.where("username", isEqualTo: _username).getDocuments();
    return result.documents.isEmpty;
  

//Gets called on sign up button pressed.
Future<void> validateAndSubmit() async 
    final valid = await usernameCheck(_username);
    if (!valid) 
      print("Username Exists.");
     else if (validateAndSave()) 
      try 
// Signs up and save data.

【问题讨论】:

【参考方案1】:

您不能在验证器函数中执行异步操作。 你可以做的是,在调用验证器之前调用checkUsername(),假设你有一个按钮,当用户点击它时,你调用验证器,你就会有这样的东西。

onPressed: () async 
    final valid = await usernameCheck();
    if (!valid) 
        // username exists
    
    else if (_formKey.currentState.validate()) 
         // save the username or something
    

此外,您不必将用户名存储在单独的集合中,您可以只将它们存储在您的主集合中,比如说users,然后像这样编辑您的checkUsername()

 Future<bool> usernameCheck(String username) async 
    final result = await Firestore.instance
        .collection('users')
        .where('username', isEqualTo: username)
        .getDocuments();
    return result.documents.isEmpty;
  

【讨论】:

感谢您的回答。但是即使用户名不存在,valid 总是返回 false ......我已经用你的代码更新了这个问题,如果你能看一下,我很感激! 很难说,试着把你从Firebase得到的文件打印到控制台看看。 这对我有用,但前提是我更改了 Firestore 规则以允许读取未经身份验证的请求。否则我会收到“权限不足”错误。听起来对吗?我不喜欢让我的数据库对未经身份验证的请求开放。【参考方案2】:

我遇到了同样的问题,我想在用户更改用户名时自动检查用户名是否可用。因此,我必须使用“onChanged”侦听器来获取用户名更新,然后调用 usernameCheck()。但是这样一来,我们会在一秒钟内调用 usernameCheck() 太多次。

更多详情:

用户名 TextField 的每次更改都会调用一个 usernameCheck() 实例。

此外,唯一有效的实例是最新的实例,因为较早的实例只会在几个字母上调用。这就是为什么我们必须消除早期的实例。

所以我找到了解决这个问题的方法。

1。文本表单域


TextFormField(
          initialValue: user.userName,
          textInputAction: TextInputAction.next,
          style: TS_Style,
          keyboardType: TextInputType.name,
          onFieldSubmitted: (_) 
            FocusScope.of(context).requestFocus(_mailFocusNode);
          ,
          onSaved: (value) => userProvider.setUserName = value,
          validator: validateUsername,
          onChanged: availableUsername,
          decoration: TEXT_FIELD_DECORATION.copyWith(
              prefixIcon: Icon( Icons.person, color: COLOR_BACKGROUND_DARK),
              hintText: '@username',
              suffixIcon: _checkingForUsername
                  ? AspectRatio(
                      aspectRatio: 1,
                      child: Padding(
                        padding: const EdgeInsets.all(8),
                        child: CircularProgressIndicator(
                          strokeWidth: 2,
                        ),
                      ),
                    )
                  : userNameAvailable != null
                      ? (userNameAvailable ? Icon(Icons.check_sharp, color: Colors.green) : _emailCheckIcon = Icon(Icons.cancel, color: Colors.red))
                      : null),
        )

_checkingForUsername 只是一个布尔标志,用于显示加载指示器。

2。可用用户名(用户名)方法


Future<void> availableUsername(String username) async 
  //exit if the username is not valid
  if (validateUsername(username) != null) return;
  
  //save the username
  _formKey.currentState.save();
  setState(() => _checkingForUsername = true);

  userNameAvailable = await handleRequest(() => userProvider.checkUserName(username), widget.scaffoldKey.currentContext);

  setState(() => _checkingForUsername = false);
  return;

handleRequest() 是一个函数,如果出现问题,它会使用服务器函数处理其错误。

3。 checkUserName(用户名)


  ///check if the usename available or not
Future<bool> checkUserName(String calledValue) async 
    //wait a second, is the user finished typing ?
    //if the given value != [_username] this means another instance of this method is called and it will finish the mission
    await Future.delayed(Duration(seconds: 1,milliseconds: 500));
    if (calledValue != _userName) 
      print('cancel username check ');
      return null;
    
    final result = await FirebaseFirestore.instance.collection('usernames').doc(_userName).get();

    print('is Exist:  $result.exists');
    return !result.exists;


究竟发生了什么,当 checkUserName(username) 被调用时,它会等待 1.5 秒(可能只有一秒)然后比较提供者 _username(始终是最新的可用用户名(用户名)方法),它是用户名参数。如果它们不相等,它将通过返回 null 来终止进程,否则,它将继续并调用服务器。

通过这种模式,它将主要针对每个所需的调用调用服务器。

【讨论】:

以上是关于带有 Flutter 的 Firebase 中的唯一用户名的主要内容,如果未能解决你的问题,请参考以下文章

找不到文件 Flutter/Flutter.h

带有 Firebase 托管的 Flutter web 无法从存储中加载图片

带有firebase的Flutter HTTP包不适用于删除请求,但适用于发布,补丁和获取?

是啥导致“权限被拒绝”-带有 FIREBASE 和 FLUTTER 的消息

Flutter:带有 patform 通道的 Firebase 消息传递 - 重复的 FlutterActivity

带有 Firebase 云消息传递的 Flutter 2.0:onMessage 未在 Android 上调用