首页 > 解决方案 > 使用 ReactJS 和 Firebase 进行身份验证

问题描述

我是 Web 开发新手,开始学习 ReactJS。

到目前为止,构建简单的 Web 应用程序没有问题。

现在我想使用 Firebase 进行身份验证。

我知道如何使用 Firebase 对用户进行身份验证,但我无法了解如何设计前端来限制对某些页面的访问。

以前,我使用 PHP,因为我使用session变量并include包含 HTML 的部分以向用户显示。

但我不知道如何使用 Firebase 在 ReactJS 中做到这一点。

初始和失败的方法:

我想更新this.state.loggedIn并使用它来显示组件。但这不是正确的方法,因为我将两个组件都发送给显示,并且我们可以使用 Chrome 中的 React 开发人员扩展轻松更改组件的状态。

这是我的主要 index.js 代码:

import React from 'react';
import ReactDOM from 'react-dom';
import Login from './components/Login/Login';
import Home from './components/Home/Home';
import fire from './components/Fire';


class App extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            loggedIn: false,
        };

        this.authListener = this.authListener.bind(this);

    }

    componentDidMount() {
        this.authListener();
    }

    authListener() {
        fire.auth().onAuthStateChanged(user => {
            if (user) {
              // User is signed in.
                console.log(user);
                this.setState({
                    loggedIn: true
                })
            } else {
              // No user is signed in.
                this.setState({
                    loggedIn: false
                });
            }
        });

    }

    render() {

        return (
            <div>
                {this.state.loggedIn ? <Home/> : <Login/>}
            </div>
        );
    }
}

ReactDOM.render(
    <App/>, document.getElementById('app'));

在 Login.js 中,我调用了 Firebase 身份验证函数。

只是片段:

fire
    .auth()
    .signInWithEmailAndPassword(this.state.email, this.state.password)
    .catch(function (error) {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          console.log(error);
          // ...
     });

身份验证工作正常,我可以在控制台日志中看到它。

那么,我应该如何在 ReactJS + Firebase 中进行身份验证?(是否可以不使用任何其他包,如 react-routes 等?)

或者我应该为此使用云功能吗?

标签: javascriptreactjsfirebaseauthenticationfirebase-authentication

解决方案


更新:

您在 html 文件中链接的所有内容都应始终来自您的公共目录。因此,请将您的捆绑.js文件保存在您的公共目录中。

我已经为初学者写了一些节省时间的技巧。您可以在此处找到有关初学者提示的更多信息。


其实很简单。

如果您只想将所需的 html 文件发送到浏览器,则每次需要完全不同的 html 时都必须访问服务器。

你说你用过PHP。在 PHP 中,我们使用会话来了解一个人是否已登录。

所以,我们尝试在这里实现它。

首先让我们看看 PHP 中的会话是如何工作的。取自一个SO 答案

一般情况下:

  • 创建会话时将会话 ID 发送给用户。
  • 它存储在 cookie 中(默认情况下称为PHPSESSID
  • 该 cookie 由浏览器随每个请求发送到服务器
  • 服务器 (PHP) 使用包含 session_id 的 cookie 来了解哪个文件对应于该用户。

会话文件中的数据是$_SESSION, 序列化的内容(即,表示为字符串 - 使用诸如 serialize之类的函数);并且在 PHP 加载文件时取消序列化,以填充$_SESSION数组。


有时,会话 ID 不存储在 cookie 中,而是在 URL 中发送——但现在这种情况很少见。


有关更多信息,您可以查看手册的会话处理部分,其中提供了一些有用的信息。

例如,有一个关于Passing the Session ID的页面,它解释了会话 id 如何在页面之间传递,使用 cookie 或在 URL 中 - 以及哪些配置选项会影响这一点。

所以,session只是一个cookie。然后我想我们可以使用 cookie 来了解用户登录状态。

在 Firebase 中,cookie 存在问题。您只能将 cookie 名称设置为__session. Firebase 会忽略其他名称,因此您无法读取服务器上的 cookie。

您需要使用 Firebase Functions 来做一些后端工作并根据用户登录状态提供 html。

因此,在您的项目目录中设置 Firebase 函数。在根中,

$ firebase init functions

现在您必须对 Firebase 说,任何进入您的域的请求都必须调用一个函数。

为此,您必须rewritesfirebase.json文件中写入。我们的函数名称将是main.

{
  "database": {
    "rules": "database.rules.json"
  },
  "hosting": {
    "public": "/dev",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites":[{
      "source": "**",
      "function": "main"
    }]
  }
}

现在创建一个index.jsanywhere(首选项目目录的根目录,因为这是主文件)。

index.js

import express from 'express';
import * as functions from 'firebase-functions';
import fs from 'fs';
var cookieParser = require('cookie-parser')

const app = express();
app.use(cookieParser());

app.get('**', (req, res) => {
    // Check the custom set cookie for user
    // If the user is not logged-in, redirect to Login. Otherwise, redirect to Home page
    if (req.cookies.__session == 'loggedin') {
        var index = fs.readFileSync(__dirname + '/src/Home/index.html', 'utf8');
    }
    else {
        var index = fs.readFileSync(__dirname + '/src/Login/index.html', 'utf8');
    }
    res.send(index);

});

export let main = functions.https.onRequest(app);

关于以上部分的一些解释:

  1. express:用于处理请求并发送响应。

  2. firebase-functions: 由 Google 提供,用于使用 Firebase Functions。

  3. fs:我们根据用户登录状态从文件系统中读取相应的html并提供。

  4. cookie-parser: 我们使用它来轻松访问我们的 cookie。

注意:您需要将其转换为 ES5。所以使用 babel 命令来转换它(我假设你保存index.js在你的根目录中。)

$ babel index.js -d functions

我们使用 cookie 命名__session来了解用户登录状态。

如果__session设置为loggedin,我们发送用户Home html。否则,我们发送Login html.

现在,真正的问题是:“我们需要在哪里设置 cookie __session?”

我们在用户浏览器中设置 cookie。

我们利用onAuthStateChanged().

Login page component用你喜欢的方式调用这个方法:

componentDidMount() {
     this.authListener();
}


authListener() {
        fire.auth().onAuthStateChanged(user => {
            if (user) {
                // User is signed in.
                if (Cookies.get('__session') === undefined) {
                    Cookies.set('__session', 'loggedin', { expires: 3652 });
                    window.location.reload();
                }
            } else {
              // No user is signed in.
              Cookies.remove('__session');
            }
        });
    }

注意Cookies对象是从js-cookie导入的。所以,安装它。

我们在这里做的是:

  1. 首先,onAuthStateChanged()在页面加载时最初调用。

  2. 如果用户已经登录,我们进入if块。

  3. 然后我们检查__sessioncookie。这很重要,因为有时用户可以清除所有 cookie。当我们尝试读取服务器中的 cookie 时,我们得到undefined并将登录页面发送给用户。过程从 重复1

  4. 然后我们重新加载页面。当我们重新加载页面时,用户再次点击服务器。然后我们可以检查__sessioncookie 并将其发送Home html给用户。


推荐阅读