问题描述
我正在构建一个使用简单登录功能的 React 应用程序。我只使用谷歌登录,并调用 signInWithPopop
函数来处理。我创建了一个单独的类来处理所有与身份验证相关的代码。在我网站的导航栏上,如果用户未登录,我有一个登录按钮,当用户登录时会切换到个人资料按钮。
console.log(authHandler.getUser());
const[loginState,setLogin] = useState(authHandler.getUser()? true : false);
return(
<div className="navbar">
<div className="nav-options">
<NavItem name="About"></NavItem>
<NavItem name="Listings"></NavItem>
<NavItem name="Dashboard"></NavItem>
{loginState ? <NavItem name="Profile"><DropDown loginState={setLogin}></DropDown></NavItem> : <NavItem name="Login" click={() => authHandler.signIn(setLogin)}></NavItem>}
</div>
</div>
);
这是我的 authHandler 类:
import firebase from 'firebase';
export default class Auth{
constructor(){
var firebaseConfig = {
...
};
!firebase.apps.length? firebase.initializeApp(firebaseConfig) : firebase.app();
firebase.analytics();
this.provider = new firebase.auth.GoogleAuthProvider();
}
signIn(state){
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION).then(() => {
return firebase.auth().signInWithPopup(this.provider).then((result) => {
console.log("signed in " + result.user.uid);
this.user = result.user
state(true);
}).catch((error) => {
console.log(error.message);
});
}).catch((error) => {
console.log(error.message);
})
}
getUser(){
return firebase.auth().currentUser;
}
logout(state){
//Todo: logout of firebase
state(false);
}
}
我尝试在 firebase 上添加会话和本地持久性,但是当我刷新页面时,用户已注销。在这样一个单独的类中,保持持久性的正确方法是什么?我正在尝试根据最佳实践构建此应用,以便正确拆分代码并维护安全性。
谢谢!
解决方法
您应该使用 auth state observer 来在用户登录状态发生变化时获取回调。当页面首次加载时,用户总是被立即视为已退出。在从持久性加载并验证用户的令牌后不久将调用回调。使用此状态回调来确定要呈现的内容。
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// User is signed in,see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
var uid = user.uid;
// ...
} else {
// User is signed out
// ...
}
});
您可能希望显示加载屏幕,直到第一个回调告诉您该用户之前是否已登录或确实已退出。
我建议reading this for more information。
,我在 react 中实现 auth 状态的方式:
Auth.provider.tsx
import React,{
FC,createContext,useContext,useEffect,useState,} from 'react';
import { User,auth } from 'firebase/app';
interface AuthContext {
user: User | null;
loading: boolean;
}
const defaultAuthContext = { user: null,loading: false };
const AuthUserContext = createContext<AuthContext>({ ...defaultAuthContext });
export const AuthUserProvider: FC = ({ children }) => {
const [authContext,setAuthContext] = useState<AuthContext>({
user: null,loading: true,});
useEffect(
() =>
auth().onAuthStateChanged((authUser) =>
setAuthContext({ user: authUser,loading: false }),),[],);
return (
<AuthUserContext.Provider value={authContext}>
{children}
</AuthUserContext.Provider>
);
};
export const useAuthUser = () => useContext(AuthUserContext);
App.tsx
const App: React.FC = () => {
return <AuthUserProvider>
// anything
</AuthUserProvider>;
}
anycomponent.tsx
const { user,loading } = useAuthUser();
return loading ? <Loader /> : !user ? <NotLogged /> : <Logged />;
你可以在你的类中实现观察者,但每次你需要你的用户时,你都应该实现一个观察用户的 useEffect 。在提供程序中将其设为全局,使其更易于使用。
还有很多其他的方法,但我认为这是最容易使用的。