【问题标题】:How to authenticate an user in firebase-admin in nodejs?如何在nodejs的firebase-admin中对用户进行身份验证?
【发布时间】:2017-07-04 07:31:13
【问题描述】:

目前我正在 nodejs 上创建一个 Firebase API。我想在 nodejs 上使用 firebase-admin 处理所有 Firebase 的东西(如身份验证)。但是,在 firebase-admin 没有客户端的 Javascript Firebase SDK 的情况下,通过 nodejs 对用户进行身份验证的正确方法是什么?在官方documentation for admin 上,我没有为nodejs 找到一个名为signInWithEmailAndPassword 的函数(就像在客户端SDK 上一样)。只有一个函数叫做:“getUserByEmail”,但是这个函数不会检查用户是否输入了正确的密码。

这是我的表格:

<form class="sign-box" action="/login" method="post">

      <div class="form-group">
          <input id="username" name="username" type="text" class="form-control" placeholder="E-Mail"/>
      </div>
      <div class="form-group">
          <input id="password" name="password" type="password" class="form-control" placeholder="Password"/>
      </div>
      <button type="submit" class="btn btn-rounded">Sign in</button>

</form>

提交表单后,我将值传递给 nodejs 中的 API:

app.post('/login', urlencodedParser, function (req, res) {

    // getting the values

    response = {
        username: req.body.username,
        password: req.body.password

    };    

    // authenticate the user here, but how ?

});

我的第一个想法是在客户端使用 Firebase SDK 使用 signInWithEmailAndPassword 登录并获取 uid。一旦我有了 UID,我想将 UID 发送到 nodejs 并调用函数 createCustomToken 并将生成的令牌(带有一些额外的声明)返回给客户端。取回令牌后,我将使用函数 signWithCustomToken (在客户端)对用户进行身份验证。这种方法正确还是有更好的方法?

【问题讨论】:

  • 通常,用户在客户端进行身份验证。 Firebase 经过优化并设计为在客户端运行。无论如何,如果您坚持,您可以在您的服务器上使用客户端 node.js require('firebase') 库。这有你需要的客户端 API signInWithEmailAndPassword 等。
  • 是的,没错。我使用 firebase-admin 的原因是我可以向令牌添加自定义声明并将其发送回用户。但这是在 nodejs 中使用 firebase 模块进行身份验证并将令牌发回的好方法。谢谢!

标签: node.js authentication firebase-admin


【解决方案1】:

这是我的解决方案,也许它可以帮助某人(节点/反应)。出于某种原因,客户端方法signInWithEmailAndPassword 似乎在客户端和服务器上都有效。基本上,这可以让您保留默认安全规则 ".read": "auth != null",而不必使用 signInAnonymously(),从而避免创建无限数量的陈旧用户。

server:

const { firebase } = require('../../firebase/frontend');
const { firebase: admin } = require('../../firebase/backend');

const email = process.env.READ_ONLY_EMAIL;
const password = process.env.READ_ONLY_PASSWORD;

export default async (req, res) => {
  try {
    const { user } = await firebase.auth().signInWithEmailAndPassword(email, password);
    const customToken = await admin.auth().createCustomToken(user.uid);
    return res.status(200).send(JSON.stringify(customToken));
  } catch (error) {
    return res.status(404).send(error);
  }
};

client:

import fetch from 'isomorphic-unfetch';
import { useState, useEffect } from 'react';
import { firebase } from '../firebase/frontend';

const useUser = (props) => {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [isAnonymous, setIsAnonymous] = useState(true);

  const getCustomToken = async () => {
    const response = await fetch('/api/auth', { method: 'POST' });
    const json = await response.json();
    return json;
  };

  useEffect(() => {
    try {
      const unsubscribe = firebase.auth().onAuthStateChanged(async (user) => {
        // user exists
        if (user && user.email !== 'readonly@myEmailAddress.com') {
          setUser(user);
          setIsAnonymous(false);
          // else sign in user "anonymously"
        } else {
          setIsAnonymous(true);
          const token = await getCustomToken();
          firebase.auth().signInWithCustomToken(token);
        }
        setLoading(false);
      });
      return () => unsubscribe();
    } catch (error) {
      console.log('Error signing in user', error);
    }
  }, []);

  return {
    user,
    isAnonymous,
    loading
    // etc...
  };
};

export default useUser;

【讨论】:

    【解决方案2】:

    实际上,您需要使用 firebase 常规 api 进行身份验证,而不是管理员。

    首先,这将为您提供一个刷新的 firebase 令牌,而不是自定义令牌。 如果你喜欢你可以做同样的事情来获得一个自定义令牌,如果你需要一个自定义令牌,我也有一个例子。

    npm install firebase --save

    const firebase = require("firebase");
    const config = {
        apiKey: "",
        authDomain: "",
        databaseURL: "",
        projectId: "",
        storageBucket: "",
        messagingSenderId: ""
    };
    firebase.initializeApp(config);
    

    我正在发布我的登录 firebase 功能,但您可以轻松更改它以表达。

    exports.login = functions.https.onRequest((req, rsp)=>{
        const email = req.body.email;
        const password = req.body.password;
        const key = req.body.key;
        const _key = '_my_key_';
        let token = '';
        if(key === _key){           
        firebase.auth().signInWithEmailAndPassword(email,password).then((user)=>{
    //The promise sends me a user object, now I get the token, and refresh it by sending true (obviously another promise)            
    user.getIdToken(true).then((token)=>{
                    rsp.writeHead(200, {"Content-Type": "application/json"});
                    rsp.end(JSON.stringify({token:token}));
                }).catch((err)=>{
                    rsp.writeHead(500, {"Content-Type": "application/json"});
                    rsp.end(JSON.stringify({error:err}));
                });
            }).catch((err)=>{
                rsp.writeHead(500, {"Content-Type": "application/json"});
                rsp.end(JSON.stringify({error:err}));
            });
        } else {
            rsp.writeHead(500, {"Content-Type": "application/json"});
            rsp.end(JSON.stringify('error - no key'));
        }
    });
    

    注意:我正在使用此登录功能来测试我与 Postman 的其他功能,这就是我发送密钥的原因,所以我可以私下使用它。

    现在结合 ADMIN 和 FIREBASE 节点 apy,我可以在我的 firebase 上使用 HTTP 函数做很多非常有趣的事情。

    希望能有所帮助。

    【讨论】:

    • 自定义令牌示例会有很大帮助。我不知道使用 firebase.auth() 也可以在函数中工作!
    • 您是否遇到了麻烦?我的意思是使用自定义令牌?我花了一段时间才明白。
    • 如果您收到 getIdToken() is not a function,那是因为他们更新了 firebase 库并进行了另一项重大更改。现在你需要像这样解构user.then(({ user })=&gt;{ ...
    • 我不知道您可以在服务器上使用客户端 SDK,即使在文档中也是如此?无论如何,非常感谢。菜鸟问题,但是您返回给客户的那个令牌的目的是什么?此示例缺少前端实现。
    【解决方案3】:

    适用于任何服务器端 React 用户 我被带到这里是因为我试图在客户端没有 Javascript Firebase SDK 的情况下验证 firebase 中的用户。我正在构建一个服务器端渲染的反应应用程序。客户端 firebase.auth() 不适用于服务器端节点环境。

    事实证明,您可以在 componentDidMount() 内运行 firebase.auth() 命令,因为它不在服务器上运行。您可以在此处进行身份验证并获取用户的令牌,然后将其发送到云函数以进行任何需要用户身份验证的服务器端渲染。

    在服务器端,您可以使用 admin sdk 验证令牌。

    您还需要使用 firebase/app 和 firebase/auth,并在特定于浏览器的 bundle.js 中初始化 firebase,使其不包含在服务器的 bundle.js 中

    componentDidMount() {
        firebase.auth().onAuthStateChanged(function(user) {
            if (user) {
                console.log("User signed in!");
            } else {
                console.log("User NOT signed in!");
            }
        });
    }

    【讨论】:

      猜你喜欢
      • 2020-07-25
      • 2017-09-12
      • 2019-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-11
      相关资源
      最近更新 更多