如何在nodejs中的firebase-admin中验证用户?

时间:2017-07-04 07:31:14

标签: node.js authentication firebase-admin

目前我正在nodejs上创建Firebase API。我想在nodejs上使用firebase-admin处理所有Firebase内容(例如身份验证)。但是,如果没有客户端的Javascript Firebase SDK,在firebase-admin 中对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 (在客户端)来验证用户。这种方式是正确的还是有更好的方法?

3 个答案:

答案 0 :(得分:7)

实际上,对于身份验证,您需要使用firebase常规api,而不是admin。

首先,这将为您提供刷新的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函数做很多非常有趣的事情。

希望它有所帮助。

答案 1 :(得分:0)

对于任何服务器端反应用户 我被带到这里是因为我试图在没有客户端的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!");
        }
    });
}

答案 2 :(得分:0)

这是我的解决方案,也许它可以帮助某人(Node/react)。出于某种原因,客户端方法 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;