我正在使用 React 和 NodeJS 创建一个 Web 应用程序,并且我正在使用 Firebase 使用电子邮件/密码进行身份验证。 该网站有两种使用客户端 SDK 处理的登录和注册:一种用于用户,一种用于组织。
我尝试使用 Firebase Functions 和 Admin SDK 为新用户注册({"role": "user"} 或 {"role": "org"})设置自定义声明,但我面临以下问题错误:
设置自定义声明时出错:FirebaseAuthError:没有与提供的标识符对应的用户记录。
我已验证 UID 是否已正确发送到后端,但我无法设置自定义声明。 以下代码用于用户身份验证,我正在尝试设置 {"role": "user"} 自定义声明。
前端代码:
import { createUserWithEmailAndPassword } from "firebase/auth";
function emailSignUp(event) {
event.preventDefault();
createUserWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
// Signed Up
const user = userCredential.user;
let formData = new FormData(
document.getElementById("emailSignUp")
);
formData.append("uid", user.uid);
fetch(
`${process.env.REACT_APP_LOCAL_API_URL}/auth/user/register`,
{
method: "POST",
body: formData,
}
)
.then((response) => response.json())
.then((data) => {
if (data.status === "error") {
throw new Error(
"Invalid form input. Please check again."
);
} else {
console.log("Success:", data);
}
})
.catch((error) => {
console.error("Error:", error);
});
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ..
console.log(error);
});
}
相关后端代码:
import { auth } from "../config/firebase.config.js";
//storage and other dependencies are imported as well, and they're working well.
router.post("/register", filesUpload, async (req, res) => {
try {
const { name, email, phone, uid } = req.body;
const file = req.files[0];
const filename = file.originalname;
const extension = filename.split(".").pop();
const pathToFile = `/user/${email}/profile.${extension}`;
const storageRef = ref(storage, pathToFile);
const metadata = {
contentType: file.mimetype,
};
const snapshot = await uploadBytesResumable(
storageRef,
file.buffer,
metadata
);
const user = await User.create({
name,
email,
photoPathFirestore: pathToFile,
phone,
});
console.log("Successfully created new user in DB!");
//error occurs on this line, since the admin SDK is not able to find the UID.
auth.setCustomUserClaims(uid, { role: "user" })
.then(() => {
console.log("Custom claims set for user");
response_200(res, "Successfully created new user in DB");
})
.catch((error) => {
console.error("Error setting custom claims:", error);
});
} catch (err) {
console.log(err);
response_500(res, "Error occurred while updating user.");
}
});
Firebase 配置文件:
import * as dotenv from "dotenv";
import { initializeApp } from "firebase-admin/app";
import { getAuth } from "firebase-admin/auth";
import { createRequire } from "module";
const require = createRequire(import.meta.url);
dotenv.config();
const adminConfig = require(process.env.PATH_TO_KEY);
const adminApp = initializeApp(adminConfig);
const auth = getAuth(adminApp);
const config = {
apiKey: process.env.API_KEY,
authDomain: process.env.AUTH_DOMAIN,
projectId: process.env.PROJECT_ID,
storageBucket: process.env.BUCKET_ID,
messagingSenderId: process.env.MESSAGING_SENDER_ID,
appId: process.env.APP_ID,
measurementId: process.env.MEASUREMENT_ID,
};
export default config;
export { auth };
我尝试在用户尝试登录时设置自定义声明,而不是在注册时设置它们,但即使这样也会产生相同的错误。
正如 @Greg Fenton 在评论中提到的,使用 Firebase 阻止功能身份验证 确实可以作为使用 Admin SDK 的替代方案。 尽管该解决方案完全有效,但我最近找到了错误的原因。 Admin SDK 不支持使用 Firebase Auth 模拟器。 就我而言,我曾经运行
firebase emulators:start
来运行所有订阅的 Firebase 服务的模拟器,其中还包括 Auth 服务。
解决方法是运行:
firebase emulators:start --only storage,functions,<all_other_services_except_auth>
。这将确保使用您的生产身份验证服务。