代码之家  ›  专栏  ›  技术社区  ›  ssh

使用ReactJS和FireBase进行身份验证

  •  3
  • ssh  · 技术社区  · 7 年前

    我对Web开发很陌生,开始学习ReactJS。

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

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

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

    以前我用过php session 变量和 include 包含要向用户显示的HTML部分。

    但我不知道如何在使用FireBase的ReactJS中实现它。

    初始和失败方法:

    我想更新 this.state.loggedIn 然后用它来显示组件。但这不是一个正确的方法,因为我要将两个组件都发送到显示中,而且我们可以轻松地使用chrome中的react developer扩展来更改组件的状态。

    这是我的主要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等?)

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

    3 回复  |  直到 7 年前
        1
  •  1
  •   SkrewEverything    7 年前

    更新:

    HTML文件中链接的所有内容都应该来自公共目录。所以,把你的包好 .js 公用目录中的文件。

    我为初学者写了一些省时的小贴士。你可以找到更多关于初学者的提示 here .


    其实很简单。

    如果您只想向浏览器发送所需的HTML文件,那么每次需要一个完全不同的HTML时都必须点击服务器。

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

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

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

    一般情况下:

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

    会话文件中的数据是 $_SESSION ,请 序列化 (即,用字符串表示——具有如下函数 serialize ) ;并在文件由加载时取消序列化 php,填充 $课程 数组。


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


    有关更多信息,您可以查看 Session Handling 手册的一节,它给出了一些有用的 信息。

    例如,有一个关于 Passing the Session ID ,其中 解释如何使用 或者在URL中——以及哪些配置选项会影响这一点。

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

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

    您需要使用firebase函数来完成一些后端工作,并根据用户登录状态提供HTML服务。

    因此,在项目目录中设置firebase函数。在根部,

    $ firebase init functions
    

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

    要做到这一点,你必须写作 rewrites 在你的 firebase.json 文件。我们的函数名是 main .

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

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

    索引.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 :由谷歌提供,用于使用FireBase功能。

    3. fs :我们根据用户登录状态从文件系统读取合适的HTML并提供服务。

    4. cookie-parser :我们使用它很容易访问我们的cookie。

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

    $ babel index.js -d functions
    

    我们正在使用名为的cookie _会议 了解用户登录状态。

    如果 _会议 设置为 loggedin ,我们发送给用户 Home html .否则,我们发送 Login HTML .

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

    我们在用户浏览器中设置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. 然后我们检查 _会议 饼干。这很重要,因为有时用户可以清除所有cookie。当我们试图读取服务器中的cookie时,我们会 undefined 我们将登录页面发送给用户。过程重复自 1 .

    4. 然后我们重新加载页面。当我们重新加载页面时,用户再次点击服务器。然后我们可以检查 _会议 饼干和发送 主页 HTML 给用户。

        2
  •  0
  •   Cisco    7 年前

    以前,我使用了PHP,其中我使用了session变量和include来包含要向用户显示的HTML部分。

    FireBase有多种方式来保持其身份验证状态,如下所述: https://firebase.google.com/docs/auth/web/auth-state-persistence

    默认情况下是 local .在网上,这是 localStorage .这对您来说可能是一个巨大的变化,因为通常身份验证状态是在服务器端和客户机端完成的某种会话或cookie中。

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

    但是有了FireBase,一切都在客户端完成。一旦用户成功通过身份验证,您将可以访问他们的身份验证令牌,如下所述: https://firebase.google.com/docs/auth/users#auth_tokens

    有了这个令牌,您需要在服务器端进行验证,如下所述: https://firebase.google.com/docs/auth/admin/verify-id-tokens 以保护/保护任何API访问。

    但是为了保护React应用程序中的某些页面,您需要验证 本地存储 在某种中间件中。最好在您的react lifecycle方法之一中有一个auth状态的监听器: https://firebase.google.com/docs/reference/js/firebase.auth.Auth#onAuthStateChanged

    在应用程序中的任何时候,身份验证状态都将变为无效,从而阻止它们查看页面。

        3
  •  0
  •   Gabriel Carneiro    7 年前

    好吧,我向你展示了如何在React应用程序上使用FireBase认证。我只是想让你知道这不是 正确的方法 你会找到很多方法。

    我们开始吧,首先我使用谷歌认证,我有一个名为 firebase.service.js 我在那里处理授权。文件如下:

    import firebase from 'firebase';
    
    import { firebaseConfig } from './private';
    
    
    export const firebaseApp = firebase.initializeApp(firebaseConfig);
    
    export const auth = firebase.auth();
    export const db = firebase.database();
    
    export function loginGoogle(/* options */) {
      const provider = new firebase.auth.GoogleAuthProvider();
    
      return firebase.auth().signInWithPopup(provider);
    }
    

    这个 firebaseConfig 对象如下:

    const firebaseConfig = {
        apiKey: API_KEY,
        authDomain: AUTH_DOMAIN,
        databaseURL: DB_URL,
        projectId: PROJECT_ID,
        storageBucket: STORE_BUCKET,
        messagingSenderId: MSG_SENDER,
    };
    

    你可以在FireBase控制台上找到它。

    在安装应用程序的索引文件中,我将 ReactDOM.render 方法进行身份验证检查,以确定是否记录用户。索引如下:

    import React from 'react';
    import ReactDOM from 'react-dom';
    import firebase from 'firebase';
    import './index.css';
    import App from './App';
    import registerServiceWorker from './registerServiceWorker';
    
    import { auth } from './services';
    
    auth.setPersistence(firebase.auth.Auth.Persistence.LOCAL).then(() => {
      const stop = auth.onAuthStateChanged(() => {
        ReactDOM.render(<App />, document.getElementById('root'));
        stop();
      });
    });
    
    registerServiceWorker();
    

    现在,您可以确定,如果用户离开并返回应用程序,如果会话仍然有效,他将不需要再次登录。

    下一步是创建 PrivateRoute 组件。以下是我所做的:

    import * as React from 'react';
    import { Redirect, Route } from 'react-router-dom';
    import PropTypes from 'prop-types';
    
    import { auth } from '../services';
    
    function PrivateRoute({ component: Component, ...rest }) {
      const toRender = propsRender => (
        auth.currentUser ?
          <Component {...propsRender} /> :
          <Redirect
            to={{
              pathname: '/',
              state: { from: propsRender.location },
            }}
          />
      );
    
      return <Route {...rest} render={toRender} />;
    }
    
    PrivateRoute.propTypes = {
      component: PropTypes.func.isRequired,
      path: PropTypes.string.isRequired,
    };
    
    export default PrivateRoute;
    

    在这里,您可以看到该函数检查是否存在任何记录的用户,否则它会将用户发送回根路径。注意我正在导入 auth 来自 ./services 不是来自 firebase ,因为此身份验证是在 firebase.service.js版本 ,然后在所有应用程序中使用它。

    现在你可以用这个了 私生路 作为一种常见的路由,不同之处在于它将检查用户是否被记录。以这个为例:

    import * as React from 'react';
    import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
    import { Layout } from 'antd';
    import moment from 'moment';
    
    import 'moment/locale/pt-br';
    import 'antd/dist/antd.css';
    
    import { PrivateRoute, MainLogged, Login, Navbar, Page404 } from './components';
    
    const { Header } = Layout;
    
    moment.locale('pt-br');
    
    function Main() {
      return <Redirect to="/login" />;
    }
    
    function App() {
      return (
        <BrowserRouter>
          <Layout>
            <Header style={{ paddingLeft: '0', backgroundColor: '#096dd9' }}>
              <Navbar />
            </Header>
            <Switch>
              <Route exact path="/" component={Main} />
              <Route exact path="/login" component={Login} />
              <PrivateRoute path="/app" component={MainLogged} />
              <Route component={Page404} />
            </Switch>
          </Layout>
        </BrowserRouter>
      );
    }
    
    export default App;
    

    如你所见 PrivateRouse 正在并排使用 Route 组件来自 react-router .

    我认为这就是一切,如果你想问任何其他的问题,只要评论,如果你想看看我从哪里得到这些代码的项目,你可以找到它 here .