如何在 React Firebase 中进行持久登录?

Posted

技术标签:

【中文标题】如何在 React Firebase 中进行持久登录?【英文标题】:How do make a persistence sign in in React Firebase? 【发布时间】:2021-03-16 04:39:04 【问题描述】:

我正在使用 Firebase Auth 构建一个应用,我有一个登录功能,但它不会持续存在。如何使该登录功能持续存在,以便用户可以刷新应用程序或在另一个选项卡中打开应用程序但仍处于登录状态? 这是我的登录信息:

const signIn = () => 
        auth
            .signInWithPopup(provider)
            .then((result) => 
                console.log(result);
                dispatch(
                    type: actionTypes.SET_USER,
                    user: result.user,
                );
            )
            .catch((error) => 
                alert(error.message);
            );
        history.push("/account");
    ;

我的 firebase.js:

import firebase from 'firebase';

// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = 
   // firebase config
  ;

  const firebaseApp = firebase.initializeApp(firebaseConfig);
  const db = firebaseApp.firestore();
  const auth = firebase.auth();
  const provider = new firebase.auth.GoogleAuthProvider();
  const storage = firebase.storage();

  export  auth, provider, storage ;
  export default db;

我试过了:

const signIn = async () => 
        await auth.setPersistence(firebase.auth.Auth.Persistence.SESSION);
        await auth
            .signInWithPopup(provider)
            .then((result) => 
                dispatch(
                    type: actionTypes.SET_USER,
                    user: result.user,
                );
            )
            .catch((error) => 
                alert(error.message);
            );
        history.push("/account");
    ;

还有这个:

const login = () => 
        auth.setPersistence(firebase.auth.Auth.Persistence.SESSION)
        .then(function() 
          return auth.signInWithPopup(provider)
                  .then((result) => 
                      console.log(result);
                      dispatch(
                          type: actionTypes.SET_USER,
                          user: result.user,
                      );
                  )
                  .catch((error) => 
                      alert(error.message);
                  );
        )
        .catch(function(error) 
          var errorCode = error.code;
          var errorMessage = error.message;
        );
    ;

但它不起作用。有什么建议?谢谢

编辑#1

这是我的 reducer.js:

export const initialState = 
    user: null
;

export const actionTypes = 
    SET_USER: "SET_USER"
;

const reducer = (state, action) => 
    console.log(action);

    switch(action.type) 
        case actionTypes.SET_USER:
            return 
                ...state,
                user: action.user
            
        default: 
            return state;
    


export default reducer;

在 App.js 中,我检查用户是否不为空:

<Router>
      <div className="app">
        !user ? (
          <>
            <PublicTopbar />
            <Switch>
              <Route path="/sign-in">
                <Login />
              </Route>
            </Switch>
          </>
        ) : (
          // My components
        )

即使在我登录后,当我打开另一个标签页时,应用程序仍会要求我再次登录

【问题讨论】:

有什么不好的?你观察到什么可以复制?请编辑问题以明确。 登录不持久(登录后,刷新或打开应用的其他点按,需要重新登录) 请编辑问题以更详细地解释,显示无法按您期望的方式工作的代码。我们应该能够复制你所拥有的并重现你的观察。我在这里看不到任何代码来检查用户是否已登录并相应地呈现。这不会自动发生。 @DougStevenson 我更新了问题,请看一下。谢谢。 我仍然没有看到任何检查用户登录状态的代码。 【参考方案1】:

在大多数平台上,您不必配置持久性,因为它是默认设置的。

需要做的是检测用户是否使用onAuthStateChanged 处理程序登录,如getting the signed in user 上的文档所示:

firebase.auth().onAuthStateChanged(function(user) 
  if (user) 
    // User is signed in.
   else 
    // No user is signed in.
  
);

一旦user 在此回调中有一个值,您就可以确定用户已登录。请注意,在页面加载时最初可能会使用null 调用侦听器,因为此时 Firebase 身份验证可能正在验证持久化的凭据。

【讨论】:

我已经更新了问题,请看一下。谢谢【参考方案2】:

实现此目的的最简单方法是使用本地存储。下面的代码是用 Redux Actions 编写的,但是你可以修改它以获得正常的 post 请求功能。

//Firebase Api
const loginInstance = axios.create(
    baseURL:"https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key="+API_KEY
)

//Send login request to Firebase
const login = (email, password) =>

    const postData = 
        email: email,
        password: password,
        returnSecureToken:true
    

    return dispatch =>
    

        loginInstance.post("", postData)
            .then(res =>
            
                dispatch(setLoginStatus(res.data.idToken, res.data.email))

                localStorage.setItem("token", res.data.idToken); //<==
                localStorage.setItem("email", res.data.email);  //<==

            )
            .catch(err => dispatch(error(err.response.data.error.message)))
    


//Check if already logged in 
const checkLoginStatus = () =>

    return dispatch =>
    
        const token = localStorage.getItem("token") //<==
        const email = localStorage.getItem("email")//<==

        if (!token)
        dispatch(logout())
        else
        dispatch(setLoginStatus(token, email))  
    


//Logout & Cleanup Localstorage
const logout = () =>

    localStorage.removeItem("token") //<==
    localStorage.removeItem("email")//<==

    return 
        type: actionTypes.LOGOUT,
    




  //Check if already logged in
  useEffect(() =>
  
    dispatch(actions.checkLoginStatus())
  , [])


 // Normal Routes
  if(isAuthenticated)
  
   //Do Something
  

【讨论】:

我更新了问题,请看一下。谢谢 您是否尝试过我之前发布的这种方法中的 Firebase 登录请求。 //Firebase Api const loginInstance = axios.create( baseURL:"identitytoolkit.googleapis.com/v1/… )

以上是关于如何在 React Firebase 中进行持久登录?的主要内容,如果未能解决你的问题,请参考以下文章

React Native - Firebase 身份验证持久性不起作用

如果 Firebase 令牌在 React 应用程序中过期,如何不调用任何 api 端点?

如何在没有 Redux 的情况下将状态保存在本地存储 React 中?

如何在 React 应用程序中处理 Firebase onAuthStateChanged 并相应地路由用户?

如何在 React Native + Expo 下使用 SAML 对 Firebase 中的用户进行身份验证

如何从持久化中排除某些 Firebase 数据库节点?