在使用 firebase/auth 和 react-native 验证 his/her 电子邮件后,如何在不创建整个登录页面的情况下立即登录用户?
How can I log in a user right after his/her email has been verified using firebase/auth and react-native without creating a whole landing page?
注意:我见过this question,但是为了验证用户而创建整个着陆页似乎有点过分。
我使用 firebase/auth
通过电子邮件和密码向我的本机反应应用程序添加了登录功能。到目前为止效果很好,我没有遇到任何问题。
然后我继续向新用户发送一封验证电子邮件,并且在验证电子邮件后只允许 him/her 使用该应用程序。同样,这里没有问题。
下一步是在验证电子邮件后立即登录用户。这就是我卡住的地方,因为 onAuthStateChanged
事件处理程序在用户按下电子邮件中的验证 link 后不会更新。
有没有办法实时监听emailVerified
状态?我尝试使用 setInterval()
进行轮询,但这不是很好,因为验证和登录之间存在明显的延迟。我读到了一个可以传递给 sendEmailVerification
的 continueLink,但我不知道如何在 react-native 中实现它。
我使用的是 Expo
,因此是 Firebase SDK,而不是 Firebase React Native 包。
这是我用于注册的代码:
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);
}
});
所以最后我确实遵循了this question,但是为了适应我的需要我做了一些改动。我会 post 我的步骤给任何做同样事情的人。
- 使用
firebase init
创建一个简单的静态网站并将其托管在 firebase 或其他地方(检查您的 firebase 控制台中的托管选项卡以开始使用)
- 按照 this guide 在网站上创建适当的处理程序
- 将以下内容添加到您的
verificationHandler
以更新用户(不要忘记导入 firestore)(我通过 continueURL
发送用户 ID,但可能有更好的方法)
// 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.";
});
- 在您的 firebase 控制台中进入身份验证 -> 模板并将操作 url 更改为您托管网站的 url
- 将 firestore 文档的侦听器添加到您的 react-native 应用程序
const onUserDataChanged = (uid, callback) => {
onSnapshot(doc(firestore, "users", uid), doc => callback(doc.data()));
}
- 使用回调中的数据更新应用中的登录状态
// 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>
);
};
注意:我见过this question,但是为了验证用户而创建整个着陆页似乎有点过分。
我使用 firebase/auth
通过电子邮件和密码向我的本机反应应用程序添加了登录功能。到目前为止效果很好,我没有遇到任何问题。
然后我继续向新用户发送一封验证电子邮件,并且在验证电子邮件后只允许 him/her 使用该应用程序。同样,这里没有问题。
下一步是在验证电子邮件后立即登录用户。这就是我卡住的地方,因为 onAuthStateChanged
事件处理程序在用户按下电子邮件中的验证 link 后不会更新。
有没有办法实时监听emailVerified
状态?我尝试使用 setInterval()
进行轮询,但这不是很好,因为验证和登录之间存在明显的延迟。我读到了一个可以传递给 sendEmailVerification
的 continueLink,但我不知道如何在 react-native 中实现它。
我使用的是 Expo
,因此是 Firebase SDK,而不是 Firebase React Native 包。
这是我用于注册的代码:
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);
}
});
所以最后我确实遵循了this question,但是为了适应我的需要我做了一些改动。我会 post 我的步骤给任何做同样事情的人。
- 使用
firebase init
创建一个简单的静态网站并将其托管在 firebase 或其他地方(检查您的 firebase 控制台中的托管选项卡以开始使用) - 按照 this guide 在网站上创建适当的处理程序
- 将以下内容添加到您的
verificationHandler
以更新用户(不要忘记导入 firestore)(我通过continueURL
发送用户 ID,但可能有更好的方法)
// 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.";
});
- 在您的 firebase 控制台中进入身份验证 -> 模板并将操作 url 更改为您托管网站的 url
- 将 firestore 文档的侦听器添加到您的 react-native 应用程序
const onUserDataChanged = (uid, callback) => {
onSnapshot(doc(firestore, "users", uid), doc => callback(doc.data()));
}
- 使用回调中的数据更新应用中的登录状态
// 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>
);
};