带有 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 中的唯一用户名的主要内容,如果未能解决你的问题,请参考以下文章
带有 Firebase 托管的 Flutter web 无法从存储中加载图片
带有firebase的Flutter HTTP包不适用于删除请求,但适用于发布,补丁和获取?
是啥导致“权限被拒绝”-带有 FIREBASE 和 FLUTTER 的消息