Как аутентифицировать пользователя в firebase-admin в nodejs?

На данный момент я создаю API Firebase на nodejs. Я хотел бы обрабатывать все вещи Firebase (например, аутентификацию) с помощью firebase-admin на nodejs. Но как правильно аутентифицировать пользователя через nodejs в firebase-admin без Javascript Firebase SDK на стороне клиента? В официальной документации для администратора я не нашел функцию под названием < strong> signInWithEmailAndPassword (как в SDK на стороне клиента) для nodejs. Есть только функция под названием "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>

После отправки формы я передаю значения своему API в nodejs:

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 (на стороне клиента) для аутентификации пользователя. Это правильный способ или есть лучший способ?


person Harry    schedule 04.07.2017    source источник
comment
Обычно пользователь аутентифицируется на стороне клиента. Firebase оптимизирована и предназначена для работы на стороне клиента. В любом случае, если вы настаиваете, вы можете использовать клиентскую библиотеку node.js require('firebase') на своем сервере. У него есть API на стороне клиента, которые вам нужны signInWithEmailAndPassword и т. Д.   -  person bojeil    schedule 04.07.2017
comment
Да, это правда. Причина, по которой я использую firebase-admin, заключается в том, что я могу добавлять пользовательские утверждения к токену и отправлять их обратно пользователю. Но это хороший подход к использованию модуля firebase в nodejs для аутентификации и отправки токена обратно. Спасибо!   -  person Harry    schedule 06.07.2017


Ответы (3)


На самом деле для аутентификации вам нужно будет использовать обычный API Firebase, а не администратора.

Сначала вы получите обновленный токен 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, я могу делать много очень интересных вещей с помощью функций HTTP на моей firebase.

Надеюсь, это как-то поможет.

person Pablo Palacios    schedule 25.07.2017
comment
Пример нестандартного токена будет очень полезен. Я не знал, что использование firebase.auth () будет работать и в функциях! - person Riël; 02.07.2018
comment
У вас проблемы с тем, чтобы заставить его работать? Я имею в виду использование специального токена? мне потребовалось время, чтобы понять. - person Pablo Palacios; 02.07.2018
comment
Если вы получили getIdToken() is not a function, это потому, что они обновили библиотеку firebase другим критическим изменением. Теперь вам нужно деструктурировать user следующим образом: .then(({ user })=>{ ... - person corysimmons; 07.05.2020
comment
Я понятия не имел, что вы можете использовать клиентский SDK на сервере, это даже в документации? В любом случае большое спасибо за это. Нубский вопрос, но какова цель этого токена, который вы возвращаете клиенту? В этом примере отсутствует реализация внешнего интерфейса. - person Operator; 18.07.2021

Для любых пользователей React на стороне сервера. Меня привели сюда, потому что я пытался аутентифицировать пользователей в firebase без Javascript Firebase SDK на стороне клиента. Я создаю приложение для реагирования на стороне сервера. Клиентская firebase.auth () не работает в серверной среде узла.

Оказывается, вы можете запускать команды firebase.auth () внутри componentDidMount (), потому что это не выполняется на сервере. Здесь вы можете пройти аутентификацию и получить токен пользователя, а затем отправить его в облачную функцию для любого рендеринга на стороне сервера, требующего аутентификации пользователя.

Затем на стороне сервера вы можете проверить токен с помощью sdk администратора.

Вам также потребуется firebase / app и firebase / auth и инициализировать firebase в вашем браузере bundle.js, чтобы он не был включен в bundle.js вашего сервера.

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

person Matthew Rideout    schedule 29.01.2018

Это мое решение, может быть, оно кому-то поможет (Узел / реакция). По какой-то причине клиентский метод 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 !== '[email protected]') {
          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;
person Operator    schedule 19.07.2021