javascript - 使用 ReactJS 和 Firebase 进行身份验证

标签 javascript reactjs firebase authentication firebase-authentication

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

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

现在我想使用 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 等?)

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

最佳答案

更新:

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

我已经为初学者写了一些节省时间的技巧。您可以找到更多关于初学者的提示 here .


其实很简单

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

你说你用的是PHP。在 PHP 中,我们使用 session 来了解一个人是否登录。

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

首先让我们看看 PHP 中的 session 是如何工作的。取自 SO Answer

In the general situation :

  • the session id is sent to the user when his session is created.
  • it is stored in a cookie (called, by default, PHPSESSID)
  • that cookie is sent by the browser to the server with each request
  • the server (PHP) uses that cookie, containing the session_id, to know which file corresponds to that user.

The data in the sessions files is the content of $_SESSION, serialized (ie, represented as a string -- with a function such as serialize) ; and is un-serialized when the file is loaded by PHP, to populate the $_SESSION array.


Sometimes, the session id is not stored in a cookie, but sent in URLs, too -- but that's quite rare, nowadays.


For more informations, you can take a look at the Session Handling section of the manual, that gives some useful informations.

For instance, there is a page about Passing the Session ID, which explains how the session id is passed from page to page, using a cookie, or in URLs -- and which configuration options affect this.

因此,session 只是一个 cookie。那么我想我们可以使用 cookie 来了解用户登录状态。

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

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

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

$ firebase init functions

现在您必须告诉 Firebase,任何到达您域的请求都必须调用一个函数。

为此,您必须在 firebase.json 文件中编写 rewrites。我们的函数名称将是 main

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

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

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

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

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

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

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

我们使用 onAuthStateChanged()

在您的登录页面组件中调用此方法,例如:

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 block 。

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

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

关于javascript - 使用 ReactJS 和 Firebase 进行身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51064424/

相关文章:

firebase - Firebase 身份验证自定义声明和没有写入权限的 Firestore 文档有什么区别?

javascript - html5消息多实例

javascript - JQuery 对新元素没有影响

javascript - 如何将 event.target.value 传递给单独的 js 文件?

javascript - 为对象数组创建新属性时对象不可扩展错误

android - play-services-ads 与 appcompat 冲突

java - 查询 Firestore 中集合中的不同字段

javascript - 是否有用于强制方法签名的 Javascript 库?

javascript - 为什么我的指令中的值没有传递到函数中?

javascript - ReactJS 中的 "IndexOf"函数不像 vanilla JS 方法那样工作