【问题标题】:Unique username in Firebase with Flutter带有 Flutter 的 Firebase 中的唯一用户名
【发布时间】: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.

【问题讨论】:

    标签: firebase flutter dart google-cloud-firestore firebase-authentication


    【解决方案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 来终止进程,否则,它将继续并调用服务器。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-29
      • 2021-11-19
      • 2016-05-16
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多