【问题标题】:Firebase verify email password in cloud functionFirebase在云功能中验证电子邮件密码
【发布时间】:2019-01-16 01:25:39
【问题描述】:

我需要接受自定义用户名进入我的网站(来自账单的要求,严格限制字母数字。)并且这些用户名应该可以与用户的电子邮件地址互换以进行登录。

我允许用户通过标准的 Firebase 电子邮件密码身份验证使用他们的电子邮件和密码进行注册和登录。用户在 biller 处注册,然后通过 postback 将自定义生成的用户名返回给应用程序。

我创建了一个用户名表,其中包含每个用户名所属的用户的 UID(最初有电子邮件,帐单生成的用户名)

当用户尝试登录时,我会转到用户名表并查找 UID。此时我想使用刚刚查到的UID,以及用户提供的密码,通过标准 firebase 身份验证系统登录用户。

我无法找到任何方法来验证用户的密码是否有效,而不是在云函数中查找的用户帐户,以便我可以生成自定义令牌。

我可以通过用户名查找用户,找到电子邮件,将其发送回客户端并允许使用该电子邮件和用户提供的密码进行登录,但我希望避免使用它,因为这将允许用户名和电子邮件地址被不良行为者相互关联。

【问题讨论】:

  • 我不确定我是否理解。您是否正在尝试构建用户名+密码身份验证?如果是这样,请查看此示例:github.com/firebase/functions-samples/tree/Node-8/…
  • @FrankvanPuffelen 我正在尝试添加将用户名(非电子邮件)与现有身份验证系统相关联的功能。
  • 有效地(从您给出的示例中)github.com/firebase/functions-samples/blob/Node-8/… 需要针对内部身份验证系统进行验证(使用电子邮件从用户记录中查找。)我需要验证函数的调用者应该收到一个令牌返回
  • 将名称与 Firebase 身份验证配置文件相关联已在此处介绍了很多次,例如stackoverflow.com/questions/31038611/…。我认为您的方法不同,但是很难将其解析为我脑海中的代码。你能显示重现你卡住的最小代码吗?
  • 我认为您误解了我的需要。我现在将尝试再编辑一些问题。我需要用户能够使用用户名(与电子邮件分开)和密码登录。我可以根据用户名查找用户,但我无法验证他们的密码是否正确

标签: firebase firebase-authentication


【解决方案1】:

在您的云功能中,您可以安装和使用除firebase-admin 之外的firebase 包,并像初始化网页一样对其进行初始化。这样您就可以使用 admin SDK 找到用户名的电子邮件,然后使用云功能中的firebase 进行身份验证,使用signInWithEmailAndPassword。如果成功,您可以生成自定义令牌并将其发送给客户端。

我不知道这是否是最好的方法,但它有效。

【讨论】:

  • 这听起来可行……去试试吧……非常感谢!
  • 在这种情况下,您是否有机会就如何安装/初始化 Firebase 提供一些指导?我正在努力让身份验证客户端初始化
  • 谢谢!搞定了:)
  • 对不起,现在才看到你的消息,很高兴它成功了! =)
  • @darksoulsong 我实际上最终使用了其余的 API cloud.google.com/identity-platform/docs/reference/rest/client
【解决方案2】:

下面是Ricardo's answer 的实现(使用 REST)。目标是允许备用登录系统与电子邮件登录并行。这是做什么的:

  1. 输入用户名
  2. 在数据库中查找匹配的电子邮件
  3. 根据该电子邮件验证提供的密码
  4. 返回电子邮件,在客户端使用signInWithEmailAndPassword()

它需要一个名为users 的数据库集合,以用户名作为关键字并包含用户的电子邮件地址。我在内部调用了用户名code(可以更改)。确保更新 API 密钥:

// Firebase dependencies.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();

// Axios, for REST calls.
const axios = require('axios');
const apiKey = '[YOUR API KEY]';
const signInURL = 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=' + apiKey;


exports.getEmailWithCodeAndPassword = functions.https.onCall((data, context) => {
  // Require code and passowrd.
  data = data || {};
  if (!(data.code && data.password)) {
    throw new functions.https.HttpsError('failed-precondition', 'The function must be called with fields: code and password.');
  }

  // Search for user's email, sign in to verify email, and return the email for client-side login.
  return db.collection('users').doc(data.code).get().then(doc => {
    // Throw if the code is not in the users DB.
    if (!doc.data()) {
      throw {
        code: 'auth/user-not-found',
        message: 'There is no user record corresponding to this identifier. The user may have been deleted.',
      };
    }

    // Retrieve the email and attempt sign-in via REST.
    const email = doc.data().email;
    return axios.post(signInURL, {
      email: email,
      password: data.password,
      returnSecureToken: true,
    }).catch(e => {
      throw {
        code: 'auth/wrong-password',
        message: 'The password is invalid or the user does not have a password.',
      };
    });
  }).then(res => {
    // Return the email after having validated the login details.
    return res.data.email;
  }).catch(e => {
    // Throw errors.
    throw new functions.https.HttpsError('unknown', e.message);
  });
});

这不是最有效的(在我的测试中约为 500 毫秒),但它确实有效。另一种方法是使用admin.auth().listUsers 执行步骤1-2,这也给出了盐/散列,然后使用Firebase's custom scrypt 来检查提供的密码与散列。这将避免需要 REST 调用,这是损失的大部分时间,但这会很困难,因为自定义 scrypt 不在 JS 中。

我还尝试使用 Firebase 客户端 SDK 而不是 REST 来实现,但它的速度差不多,并且具有更多更大的依赖项(90MB 和 6400 个文件,而 Axios 为 500KB/67 个文件)。如果有人好奇,我也会在下面复制该解决方案:

// Firebase dependencies.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const firebaseClient = require('firebase');
admin.initializeApp();
const db = admin.firestore();

// Configure and initialise Firebase client SDK.
var firebaseConfig = {
  // [COPY YOUR CLIENT CONFIG HERE (apiKey, authDomain, databaseURL, etc)]
};
firebaseClient.initializeApp(firebaseConfig);

exports.getEmailWithCodeAndPassword = functions.https.onCall((data, context) => {
  // Require code and passowrd.
  data = data || {};
  if (!(data.code && data.password)) {
    throw new functions.https.HttpsError('failed-precondition', 'The function must be called with fields: code and password.');
  }

  // Search for user's email, sign in to verify email, and return the email for client-side login.
  let email;
  return db.collection('users').doc(data.code).get().then(doc => {
    if (!doc.data()) {
      throw {
        code: 'auth/user-not-found',
        message: 'There is no user record corresponding to this identifier. The user may have been deleted.',
      };
    }

    // Retrieve the email and attempt sign-in.
    email = doc.data().email;
    return firebaseClient.auth().signInWithEmailAndPassword(email, data.password);
  }).then(res => email).catch(e => {
    throw new functions.https.HttpsError('unknown', e.message);
  });
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-21
    • 2019-07-13
    • 1970-01-01
    • 2021-04-18
    • 2016-10-13
    • 2020-10-19
    • 2018-11-11
    • 2013-07-11
    相关资源
    最近更新 更多