Firestore:如果规则失败,如何停止创建用户帐户? [复制]

Posted

技术标签:

【中文标题】Firestore:如果规则失败,如何停止创建用户帐户? [复制]【英文标题】:Firestore: How to stop user account being created if a rule has failed? [duplicate] 【发布时间】:2018-11-23 10:59:07 【问题描述】:

我有一个简单的注册表单,用户可以在其中设置他们的详细信息,包括需要唯一的用户名。

我已经编写了一个规则来验证用户名是否已经存在(有效),但即使注册失败,用户帐户也已创建。

注册脚本示例(剥离):

try 
    // This creates a user on submit of the form.
    const data = await fb.auth.createUserWithEmailAndPassword(this.email, this.password)

    // Use the uid we get back to create a user document in the users collection.
    await db.collection('users').doc(data.user.uid).set(
      username: this.username, // This fails in the rule if it exists.
      firstName: this.firstName,
      lastName: this.lastName
    )
 catch (error) 
    console.log(error)

创建用户文档的调用失败,因为用户名不是唯一的(这是预期的),但在流程中的这一点上,用户已经在 Firebase 中创建了!

如果他们随后选择另一个用户名,他们将无法继续,因为 Firestore 已经看到使用相同电子邮件的用户。

有没有更好的方法来创建这个流程?

理想情况下,如果用户文档的创建以某种方式失败,我根本不想创建用户。

谢谢!

可能的解决方案:

我在想如果 try/catch 块失败,我可以在创建用户后立即删除用户:

await data.user.delete() // ...but this seems hacky?

【问题讨论】:

你有没有想过使用云功能?如果对这种方法开放,可以获得一些示例代码。可以很容易地拥有一个 http 函数,您可以在其中进行查询以检查用户名是否可用,如果可用则创建用户,然后将记录放入 firestore。 当然,我已经将云函数用于其他东西......如果你知道如何使用它并有示例代码会很棒。 【参考方案1】:

我建议在此处使用 Cloud Functions,可能使用 http onCall 会使其变得简单易用。我尚未测试以下内容,但应该可以帮助您。

客户端代码

const createUser = firebase.functions().httpsCallable('createUser');
createUser(
    email: this.email,
    password: this.password,
    username: this.username,
    firstName: this.firstName,
    lastName: this.lastName
).then(function(result) 
  console.log(result); // Result from the function
  if (result.data.result === 'success') 
     await firebase.auth().signInWithEmailAndPassword(this.email, this.password);
   else 
      console.log('Username already exists')
  
);

云功能

exports.createUser = functions.https.onCall(async (data, context) => 
    const email = data.email; 
    const password = data.password;
    const username = data.username;
    const firstName = data.firstName;
    const lastName = data.lastName;

    const usersQuery = await admin.firestore().collection('users').where('username', '==', username).get();

    if (usersQuery.size > 0) 
        return 
            result: 'username-exists'
        
     else 
        const user = await admin.auth().createUser(
            displayName: username,
            email: email,
            password: password
        );
        await admin.firestore().collection('users').doc(user.uid).set(
            username: username,
            firstName: firstName,
            lastName: lastName
        );
        return 
            result: 'success'
        
    
);

【讨论】:

您知道如何从云函数返回 HTTP 错误响应以及错误消息吗?当请求返回时,我希望能够在客户端上触发 try / catch。 在文档中详细介绍了firebase.google.com/docs/functions/callable#handle_errors 仅供参考,我不得不用 set() 更改“.doc(user.uid).create()”...“.doc(user.uid).set()”【参考方案2】:

如果您希望某个值是唯一的,请考虑将其用作集合中的文档 ID,并禁止对该集合进行更新。

例如,由于您希望用户名是唯一的,请创建一个集合usernames,其中每个文档的 ID 是用户名,内容是使用该名称的用户的 UID。

另见:

Cloud Firestore: Enforcing Unique User Names Firebase Firestore Unique Constraints How to Enforce Unique Field Values in Cloud Firestore

【讨论】:

是的,我已经有了。检查用户名的唯一性不是问题......如果用户名存在的规则返回无效,如何防止创建用户。 啊哈...您可以通过反转调用来做到这一点:首先检查唯一性,然后再创建用户。

以上是关于Firestore:如果规则失败,如何停止创建用户帐户? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

用于在用户之间共享数据的 Firestore 安全规则

即使firestore安全规则中的文档字段不可用,也如何允许访问?

Firestore 安全规则:“PERMISSION_DENIED:权限缺失或不足。”

访问 Firestore 规则中的父文档字段

Prolog:如果规则中的一个规则失败,那么停止该程序,否则通常工作

我应该如何构建我的 Firestore 安全规则?