firebase - 如何仅在functions.auth.user().onCreate完成后才能完成登录
问题描述
我正在使用 firebase 函数,并且我有一个在用户创建时添加新集合的函数。问题是有时用户在功能完成之前已登录,因此用户已登录但尚未创建新集合(然后我有错误消息'缺少或权限不足。因为规则找不到该集合')。我该如何处理?
只有当所有东西都来自
export const createCollection = functions.auth.user().onCreate(async user => {
try {
const addLanguages = await addFirst();
const addSecondCollection = await addSecond();
async function addFirst() {
const userRef = admin.firestore().doc(`languages/${user.uid}`);
await userRef.set(
{
language: null
},
{ merge: true }
);
return 'done';
}
async function addSecond() {
// ...
}
return await Promise.all([addLanguages, addSecondCollection]);
} catch (error) {
throw new functions.https.HttpsError('unknown', error);
}
});
完成了吗?所以谷歌提供程序窗口关闭并且用户仅在此之后登录?(并且不要使用 setTimeouts 等)
解决方案
AFAIK 无法直接耦合应用程序中隐含的两个进程:
- 一方面,您在前端实现了 Google 登录流程(即使后端调用了 Auth 服务),并且;
- 另一方面,您拥有在后端执行的云功能。
您遇到的问题来自这样一个事实,即一旦Google 登录流程成功,您的用户就会登录到您的应用程序并尝试读取要由 Cloud Function 创建的文档。
在某些情况下(例如由于 Cloud Function 冷启动),当用户登录时尚未创建此文档,从而导致错误。
一种可能的解决方案是在前端设置一个 Firestore 侦听器以等待创建此文档,如下所示。请注意,以下代码仅考虑了由该addFirst()
函数创建的 Firestore 文档,因为您没有提供有关要通过创建的第二个文档的任何详细信息addSecond()
。
firebase.auth().signInWithPopup(provider)
.then(function(result) {
var token = result.credential.accessToken;
var user = result.user;
//Here we know the userId then we can set a listener to the doc languages/${user.uid}
firebase.firestore().collection("languages").doc(user.uid)
.onSnapshot(function(doc) {
if(doc.exists) {
console.log("Current data: ", doc.data());
//Do whatever you want with the user doc
} else {
console.log("Language document not yet created by the Cloud Function");
}
});
}).catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
var email = error.email;
var credential = error.credential;
// ...
});
如上所述,在上面的代码中,我们只考虑了该函数创建的第一个Firestore 文档。addFirst()
但是您可能需要等待两个文档创建完成,然后才能从前端读取它们。
因此,您可以按如下方式修改您的 CF:
export const createCollection = functions.auth.user().onCreate(async user => {
try {
await addFirst();
await addSecond();
return null;
async function addFirst() {
const userRef = admin.firestore().doc(`languages/${user.uid}`);
await userRef.set(
{
language: null
},
{ merge: true }
);
}
async function addSecond() {
// ...
}
} catch (error) {
console.log(error);
return null;
}
});
请注意,您不需要使用Promise.all()
:以下两行已经执行了对 Firestore 的两个文档写入。并且,由于您使用async/await
第二个文档,因此仅在编写第一个文档之后才编写。
const addLanguages = await addFirst();
const addSecondCollection = await addSecond();
所以你只需要在第二个文档的路径上设置监听器,你就完成了!
最后,注意做
throw new functions.https.HttpsError('unknown', error);
在您的catch
块中是您应该为可调用云函数处理错误的方式。在这里,您正在编写一个后台触发的云函数,您可以使用return null;
推荐阅读
- c# - 如何使用表单在 ASP.NET MVC 和 C# 中搜索我的表?
- docker - Jenkins 管道中的 Docker 凭据
- java - Scala 3 hello world 导入,运行 sbt 时出错
- mysql - 针对 Woocommerce 商店的 MariaDB 优化,即将推出超过 55,000 篇文章
- flutter - Flutter:使用 RepaintBoundary 截取被裁剪的小部件的屏幕截图
- c# - 如何从非活动游戏对象访问脚本?
- flutter - 热重载在特定文件中不起作用 - Flutter
- php - 如何打印多行 JSON 结果?
- c# - 防止 Visual Studio 将图像序列化为 resx 文件
- javascript - 不和谐.js | 检测消息是否包含表情符号