React - Firebase 使用单独的身份验证处理身份验证持久性 class
React - Firebase handling Auth persistence using a separate auth class
我正在构建一个使用简单登录功能的 React 应用程序。我只使用 google 登录,并调用 signInWithPopop
函数来处理它。我创建了一个单独的 class 来处理所有与身份验证相关的代码。在我网站的导航栏上,如果用户未登录,我有一个登录按钮,当用户登录后,该按钮会切换到个人资料按钮。
这就是我目前检查用户是否登录的方式(不工作):
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 class:
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 上添加会话和本地持久性,但是当我刷新页面时,用户已注销。在像这样的单独 class 中,保持持久性的正确方法是什么?我正在尝试根据最佳实践构建此应用程序,以便正确拆分代码并维护安全性。
谢谢!
您应该使用 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
// ...
}
});
您可能想要显示一个加载屏幕,直到第一个回调告诉您确定用户之前是否登录过或确实退出过。
我在 React 中实现身份验证状态的方式:
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 />;
您可以在 class 中实施观察者,但每次您需要您的用户时,您都应该实施一个 useEffect 观察用户。使其在提供程序中全局化使其更易于使用。
还有很多其他方法,但我认为这个是最容易使用的。
我正在构建一个使用简单登录功能的 React 应用程序。我只使用 google 登录,并调用 signInWithPopop
函数来处理它。我创建了一个单独的 class 来处理所有与身份验证相关的代码。在我网站的导航栏上,如果用户未登录,我有一个登录按钮,当用户登录后,该按钮会切换到个人资料按钮。
这就是我目前检查用户是否登录的方式(不工作):
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 class:
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 上添加会话和本地持久性,但是当我刷新页面时,用户已注销。在像这样的单独 class 中,保持持久性的正确方法是什么?我正在尝试根据最佳实践构建此应用程序,以便正确拆分代码并维护安全性。
谢谢!
您应该使用 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
// ...
}
});
您可能想要显示一个加载屏幕,直到第一个回调告诉您确定用户之前是否登录过或确实退出过。
我在 React 中实现身份验证状态的方式:
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 />;
您可以在 class 中实施观察者,但每次您需要您的用户时,您都应该实施一个 useEffect 观察用户。使其在提供程序中全局化使其更易于使用。
还有很多其他方法,但我认为这个是最容易使用的。