Javascript Firestore:如果规则失败,如何停止创建用户帐户?

Javascript Firestore:如果规则失败,如何停止创建用户帐户?,javascript,firebase,firebase-authentication,google-cloud-firestore,Javascript,Firebase,Firebase Authentication,Google Cloud Firestore,我有一个简单的注册表单,用户可以在其中设置他们的详细信息,包括需要唯一的用户名 我已经编写了一个规则来验证用户名是否已经存在(有效),但即使注册失败,用户帐户也已经创建 注册脚本示例(精简): try { // This creates a user on submit of the form. const data = await fb.auth.createUserWithEmailAndPassword(this.email, this.password) //

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

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

注册脚本示例(精简):

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 {
    // 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)
}
我在想,如果try/catch块失败,我可以在创建用户后立即删除该用户:

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

我建议在这里使用云函数,使用一个可能会使它变得漂亮和简单。我没有测试过下面的内容,但应该可以让你几乎达到目的

客户端代码

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'
        }
    }
});

我建议在这里使用云函数,也许使用云函数会使它变得简单和漂亮。我没有测试过下面的内容,但应该可以让你几乎达到目的

客户端代码

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'
        }
    }
});

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

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

另见:


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

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

另见:


您是否考虑过使用云功能?如果采用这种方法,可以获得一些示例代码。可以很容易地使用http功能,在该功能中,您可以执行查询以检查用户名是否可用,如果可用,则创建用户,然后将记录放入firestore。当然,我已经在用云函数做其他东西了……如果你知道如何用它来做,并且有很好的示例代码,你想过用云函数吗?如果采用这种方法,可以获得一些示例代码。可以很容易地使用http功能,在该功能中,您可以执行查询以检查用户名是否可用,如果可用,则创建用户,然后将记录放入firestore。当然,我已经在使用云函数来做其他事情了……如果你知道如何使用云函数,并且有很好的示例代码的话。你知道我如何从云函数返回HTTP错误响应以及错误消息吗?当请求返回时,我希望能够在客户端上使try/catch出错。在文档上,它将进入更多详细信息供参考,我必须使用set()更改“.doc(user.uid).create()。。。“.doc(user.uid).set()”您知道如何从云函数返回HTTP错误响应以及错误消息吗?当请求返回时,我希望能够在客户端上使try/catch出错。在文档上,它将进入更多详细信息供参考,我必须使用set()更改“.doc(user.uid).create()。。。“.doc(user.uid).set()”是的,我已经有了。检查用户名的唯一性本身并不是问题…问题是如果用户名存在的规则返回无效,如何防止创建用户。啊哈。。。您可以通过反转调用来实现这一点:首先检查唯一性,然后创建用户。是的,我已经有了。检查用户名的唯一性本身并不是问题…问题是如果用户名存在的规则返回无效,如何防止创建用户。啊哈。。。您可以通过反转调用来实现这一点:首先检查唯一性,然后创建用户。