登录后 Firebase Firestore 身份验证令牌无限循环

Bar*_*ota 7 access-token firebase reactjs google-cloud-firestore

  • 当应用程序连接到 Firestore 并且用户登录(在我们的应用程序中)时,会出现一个身份验证令牌无限循环。
  • 如果没有 Firestore 连接,则不会发生这种效果。
  • 您可以通过链接查看此处包含的 GIF 文件中的问题(见下文)。
  • 有趣的是,与 Windows 10 或 8.1(我没有在 Mac 上运行它)相比,仅当项目在 Linux Mint(19.1 Cinnamon)上运行时才会出现此问题。
  • 该项目由 Create React App 引导。

问题的视频演示

我在本教程中将 Firebase 与 ReactJS 集成:https ://www.robinwieruch.de/complete-firebase-authentication-react-tutorial

并发现其中提供的基于类的 Firebase 连接和 HOC/Context API 会话处理非常有用。但是,我不知道如何修复此身份验证令牌无限循环。

下面是负责登录/退出和 Firebase 连接的文件,以及 package.json:

索引.js:

import React from 'react';
import ReactDOM from 'react-dom';

import './index.css';
import * as serviceWorker from './serviceWorker';

import App from './App';
import Firebase, { FirebaseContext } from './components/Firebase';

ReactDOM.render(
  <FirebaseContext.Provider value={new Firebase()}>
    <App />
  </FirebaseContext.Provider>,
  document.getElementById('root')
);

serviceWorker.unregister();
Run Code Online (Sandbox Code Playgroud)

应用程序.js:

import React from 'react';
import {
  BrowserRouter as Router,
  Route,
  Switch
} from 'react-router-dom';

import Navigation from './components/Navigation';
import LandingPage from './components/LandingPage';
import SignInPage from './components/SignInPage';
import HomePage from './components/HomePage';
import HomePage2 from './components/HomePage2';

import { withAuthentication } from './components/Session';
import * as ROUTES from './components/constants/routes';

const App = () => (
  <Router>
    <Navigation />
    <hr />
    <Switch>
      <Route exact path={ROUTES.LANDING} component={LandingPage} />
      <Route path={ROUTES.SIGN_IN} component={SignInPage} />
      <Route path={ROUTES.HOME} component={HomePage} />
      <Route path={ROUTES.HOME2} component={HomePage2} />
    </Switch>
  </Router>
);
 
export default withAuthentication(App);
Run Code Online (Sandbox Code Playgroud)

Firebase / context.js:

import React, { createContext } from 'react';

const FirebaseContext = createContext(null);

export const withFirebase = Component => props => (
  <FirebaseContext.Consumer>
    {firebase => <Component {...props} firebase={firebase} />}
  </FirebaseContext.Consumer>
);
export default FirebaseContext;
Run Code Online (Sandbox Code Playgroud)

Firebase / firebase.js:

import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

const config = {
  apiKey: process.env.REACT_APP_API_KEY,
  authDomain: process.env.REACT_APP_AUTH_DOMAIN,
  databaseURL: process.env.REACT_APP_DATABASE_URL,
  projectId: process.env.REACT_APP_PROJECT_ID,
  storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
  appId: process.env.REACT_APP_ID
};

class Firebase {
  constructor() {
    app.initializeApp(config);
    this.auth = app.auth();
    this.db = app.firestore();
  }
  // Auth API
  doSignInWithEmailAndPassword = (email, password) => this.auth.signInWithEmailAndPassword(email, password);
  doSignOut = () => this.auth.signOut();
}

export default Firebase;
Run Code Online (Sandbox Code Playgroud)

Firebase / index.js:

import FirebaseContext, { withFirebase } from './context';
import Firebase from './firebase';
 
export default Firebase;
export { FirebaseContext, withFirebase };
Run Code Online (Sandbox Code Playgroud)

会话/context.js:

import { createContext } from 'react';
 
const AuthUserContext = createContext(null);
 
export default AuthUserContext;
Run Code Online (Sandbox Code Playgroud)

会话/ index.js:

import AuthUserContext from './context';
import withAuthentication from './withAuthentication';
import withAuthorization from './withAuthorization';
 
export { AuthUserContext, withAuthentication, withAuthorization };
Run Code Online (Sandbox Code Playgroud)

会话/withAuthentication.js:

import React, { useState, useEffect } from 'react';
 
import AuthUserContext from './context';
import { withFirebase } from '../Firebase';

const withAuthentication = Component => {
  const WithAuthentication = (props) => {
    const [authUser, setAuthUser] = useState(null);
    useEffect(() => {
      const listener = props.firebase.auth.onAuthStateChanged(authUser => {
        authUser
          ? setAuthUser(authUser)
          : setAuthUser(null);
      });
      return () => listener();
    }, []);
    return (
      <AuthUserContext.Provider value={authUser}>
        <Component {...props} />
      </AuthUserContext.Provider>
    );
  };
 
  return withFirebase(WithAuthentication);
};
 
export default withAuthentication;
Run Code Online (Sandbox Code Playgroud)

会话/withAuthorization.js:

import React, { useEffect } from 'react';
 
import AuthUserContext from './context';
import { withFirebase } from '../Firebase';
import * as ROUTES from '../constants/routes';

const withAuthorization = (Component) => {
  const WithAuthorization = (props) => {
    useEffect(() => {
      const listener = props.firebase.auth.onAuthStateChanged(
        authUser => {
          if (!authUser) {
            props.history.push(ROUTES.SIGN_IN);
          }
        }
      );
      return () => listener();
    }, []);
    return (
      <AuthUserContext.Consumer>
        {authUser => !!authUser && <Component {...props} />}
      </AuthUserContext.Consumer>
    );
  };

  return withFirebase(WithAuthorization);
};
 
export default withAuthorization;
Run Code Online (Sandbox Code Playgroud)

包.json:

{
  "name": "react-firebase-test",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.5.0",
    "@testing-library/user-event": "^7.2.1",
    "firebase": "^7.14.5",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-router-dom": "^5.2.0",
    "react-scripts": "3.4.1",
    "recompose": "^0.30.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "dotenv": "^8.2.0"
  }
}
Run Code Online (Sandbox Code Playgroud)