如何在用户的电子邮件使用firebase/auth验证后立即登录,并在不创建整个登录页的情况下进行本地反应



注意:我已经看到了这个问题,但创建一个完整的登录页来验证用户似乎有点过分。

我使用带有电子邮件和密码的firebase/auth为我的react原生应用程序添加了登录功能。到目前为止效果很好,我做这件事没有问题。

然后,我继续向新用户发送验证电子邮件,并只允许他/她在电子邮件验证后使用该应用程序。再说一遍,这里没有问题。

下一步是在验证电子邮件后立即登录用户。这就是我遇到的问题,因为在用户按下电子邮件中的验证链接后,onAuthStateChanged事件处理程序不会更新。

有没有办法实时监听emailVerified的状态?我尝试在setInterval()中使用轮询,但这并不好,因为在验证和登录之间有明显的延迟。我读到了一个可以传递给sendEmailVerification的continueLink,但我不知道如何在react native中实现它。

我使用的是Expo,因此使用的是Firebase SDK,而不是Firebase react本机包。

这是我注册时使用的代码:

export const signUp = async (username: string, email: string, password: string) => {
try {
const auth = getAuth();
if (email && password && username) {
// sign up 
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
// save username in firestore
await setUserName(userCredential, username);
// send Email Verification
await sendEmailVerification(userCredential.user);
return true;
}
} catch (error) {
onError(error);
}
};

这是我的onAuthStateChanged处理程序:

auth.onAuthStateChanged(authenticatedUser => {
try {
if (authenticatedUser?.emailVerified) {
setUser(authenticatedUser)
} else {
setUser(null)
}
} catch (error) {
console.log(error);
}
});

所以最后我确实回答了这个问题,但为了满足我的需求,我做了一些更改。我会为任何做同样事情的人发布我的步骤。

  1. firebase init创建一个简单的静态网站,并将其托管在firebase或其他地方(查看firebase控制台中的托管选项卡即可开始(
  2. 按照本指南在网站上创建适当的处理程序
  3. 将以下内容添加到verificationHandler中以更新用户(不要忘记导入firestore((我通过continueURL发送userId,但可能有更好的方法(
// You can also use realtime database if you want
firebase.firestore().collection("users").doc(userId).set({
emailVerified: true
}, {merge: true}).then(() => {
message.textContent = "Your email has been verified.";
}).catch((error) => {
message.textContent = "The verification was invalid or is expired. Please try to send another verification email from within the app.";
});
  1. 进行身份验证->firebase控制台中的模板,并将操作url更改为托管网站的url
  2. 在你的react原生应用程序的firestore文档中添加一个监听器
const onUserDataChanged = (uid, callback) => {
onSnapshot(doc(firestore, "users", uid), doc => callback(doc.data()));
}
  1. 使用回调中的数据更新应用程序中的登录状态
// As an example
auth.onAuthStateChanged(authenticatedUser => {
if (authenticatedUser && !authenticatedUser.emailVerified) {
unsubscribeFirestoreListener?.();
unsubscribeFirestoreListener = onUserDataChanged(authenticatedUser.uid, (data: any) => {
if (data?.emailVerified) {
setUser(authenticatedUser);
unsubscribeFirestoreListener?.();
}
});
}
}

将以下代码用于身份验证上下文。对于用户id,您应该使用"user.uid">

import React, { useState, createContext } from "react";
import * as firebase from "firebase";
import { loginRequest } from "./authentication.service";
export const AuthenticationContext = createContext();
export const AuthenticationContextProvider = ({ children }) => {
const [isLoading, setIsLoading] = useState(false);
const [user, setUser] = useState(null);
const [error, setError] = useState(null);

firebase.auth().onAuthStateChanged((usr) => {
if (usr) {
setUser(usr);
setIsLoading(false);
} else {
setIsLoading(false);
}
});

const onLogin = (email, password) => {
setIsLoading(true);
firebase.auth().signInWithEmailAndPassword(email, password)
.then((u) => {
setUser(u);
setIsLoading(false);
})
.catch((e) => {
setIsLoading(false);
setError(e.toString());
});
};
const onRegister = (email, password, repeatedPassword) => {
setIsLoading(true);
if (password !== repeatedPassword) {
setError("Error: Passwords do not match");
return;
}
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then((u) => {
setUser(u);
setIsLoading(false);
})
.catch((e) => {
setIsLoading(false);
setError(e.toString());
});
};
const onLogout = () => {
setUser(null);
firebase.auth().signOut();
};
return (
<AuthenticationContext.Provider
value={{
isAuthenticated: !!user,
user,
isLoading,
error,
onLogin,
onRegister,
onLogout,
}}
>
{children}
</AuthenticationContext.Provider>
);
};

最新更新