React - Firebase 使用单独的身份验证类处理身份验证持久性

问题描述

我正在构建一个使用简单登录功能的 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 。在提供程序中将其设为全局,使其更易于使用。

还有很多其他的方法,但我认为这是最容易使用的。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...